????ࡱ> 9 R+bjbj2'lAAAAA?BnJnJnJnJnJnJnJ$7 WRnJnJnJnJnJmnJnJmmmnJnJnJmnJmmNnNznJB `L<>Ab zD0?\m"zm HYPERLINK "http://www.blong.com/" http://www.blong.com/ BrianLong's Consultancy & Training Services Downloads Note that in addition to the files listed here, the various  HYPERLINK "http://www.blong.com/Articles.htm" articles on this Web site have links to their own files that can be downloaded.  HYPERLINK "http://www.blong.com/" \l "Archaeopteryx" Archaeopteryx for Delphi and C++Builder  HYPERLINK "http://www.blong.com/" \l "ArchaeopteryxSource" Archeopteryx source code  HYPERLINK "http://dotnet.borland.com/samples/Digger.zip" Digger for .NET, a sample game application written in Delphi for .NET  HYPERLINK "http://www.blong.com/UserGroupTalks/BUG20030403.zip" Files that accompanied my  HYPERLINK "http://www.blong.com/UserGroupTalks.htm" \l "InfoResources" Subjectively Useful Information Resources talk in Reading (3rd April 2003).  HYPERLINK "http://www.blong.com/UserGroupTalks/BUG20030211.zip" Files that accompanied my  HYPERLINK "http://www.blong.com/UserGroupTalks.htm" \l "DiggingIntoNET" Digging Deeper Into .NET talk in London (11th February 2003).  HYPERLINK "http://www.blong.com/UserGroupTalks/BUG20030114.zip" Files that accompanied my  HYPERLINK "http://www.blong.com/UserGroupTalks.htm" \l "NETInteroperability" .NET Interoperability talk in London (14th January 2003).  HYPERLINK "http://www.blong.com/UserGroupTalks/BUG20020820.zip" Files that accompanied my  HYPERLINK "http://www.blong.com/UserGroupTalks.htm" \l "Speech" Speech Synthesis & Speech Recognition talk in London (20th August 2002).  HYPERLINK "http://www.blong.com/UserGroupTalks/BUG20001121.zip" Files that accompanied my  HYPERLINK "http://www.blong.com/UserGroupTalks.htm" \l "Lists" Lists talk in London (21st November 2000).  HYPERLINK "http://www.blong.com/UserGroupTalks/BUG20001017.zip" Files that accompanied my  HYPERLINK "http://www.blong.com/UserGroupTalks.htm" \l "Docking" Drag & Dock talk in London (17th October 2000).  HYPERLINK "http://www.blong.com/UserGroupTalks/BUG20000815.zip" Files that accompanied my  HYPERLINK "http://www.blong.com/UserGroupTalks.htm" \l "Clinic" Delphi Clinic talk in London (15th August 2000).  HYPERLINK "http://www.blong.com/UserGroupTalks/BUG20000523.zip" Files that accompanied my  HYPERLINK "http://www.blong.com/UserGroupTalks.htm" \l "Actions" Actions talk in London (23rd May 2000).  HYPERLINK "http://www.blong.com/UserGroupTalks/BUG20000321.zip" Files that accompanied my  HYPERLINK "http://www.blong.com/UserGroupTalks.htm" \l "DragDrop" Drag & Drop talk in London (21st March 2000).  HYPERLINK "http://www.blong.com/UserGroupTalks/BUG19990525.zip" Files that accompanied my  HYPERLINK "http://www.blong.com/UserGroupTalks.htm" \l "MessageInABottle" Messages In A Bottle talk in London (25th May 1999).  HYPERLINK "http://www.blong.com/UserGroupTalks/BUG19990319.zip" Files that accompanied my  HYPERLINK "http://www.blong.com/UserGroupTalks.htm" \l "MessageInABottle2" Messages In A Bottle talk in Glasgow (19th March 1999).  HYPERLINK "http://www.blong.com/UserGroupTalks/BUG19990506.zip" Files that accompanied my  HYPERLINK "http://www.blong.com/UserGroupTalks.htm" \l "Interfaces" Interfaces talk, in Dublin (6th May 1999).  HYPERLINK "http://www.blong.com/UserGroupTalks/BUG19990506.zip" Files that accompanied my  HYPERLINK "http://www.blong.com/UserGroupTalks.htm" \l "Classes" Class Creation talk in Dublin (6th May 1999).  HYPERLINK "http://www.blong.com/UserGroupTalks/BUG19990506.zip" Files that accompanied my  HYPERLINK "http://www.blong.com/UserGroupTalks.htm" \l "Components2" Component Creation talk in Dublin (6th May 1999).  HYPERLINK "http://www.blong.com/UserGroupTalks/BUG19990223.zip" Files that accompanied my  HYPERLINK "http://www.blong.com/UserGroupTalks.htm" \l "Classes2" Class Creation talk in London (23rd February 1999).  HYPERLINK "http://www.blong.com/UserGroupTalks/BUG19990223.zip" Files that accompanied my  HYPERLINK "http://www.blong.com/UserGroupTalks.htm" \l "Components" Component Creation talk in London (23rd February 1999).  HYPERLINK "http://www.blong.com/UserGroupTalks/BUG19980423.zip" Files that accompanied my  HYPERLINK "http://www.blong.com/UserGroupTalks.htm" \l "COM" COM talk in Dublin (23rd April 1998). Archaeopteryx In the spirit of  HYPERLINK "http://ourworld.compuserve.com/homepages/mikes/TRex.html" \t "_blank" T-Rex, Raptor (now called  HYPERLINK "http://www.eagle-software.com/coderush.htm" \t "_blank" CodeRush) and  HYPERLINK "http://www.gexperts.org" \t "_blank" GExperts which you may have heard of, Archaeopteryx is my own prehistoric creation. This is in the file called  HYPERLINK "http://www.blong.com/Downloads/DinoSaur.zip" DinoSaur.Zip (38kb) and is a Delphi/C++Builder package. Like the other products, it is designed to customise and enhance your Delphi/C++Builder IDE. The following files are in the ZIP file: ARCHAEOPTERYX.DPL is a Delphi 3 package ARCHAEOPTERYX.BPL is a package that works with Delphi 4 and C++Builder 4 ARCHAEOPTERYX50.BPL is a package that works with Delphi 5 and C++Builder 5 Archaeopteryx offers the following features: It unhides some otherwise hidden menu items (Delphi 3 version only): Search | Show Last Compile Error View | View as Text Help | How to Use Help Help | Windows API It adds component palette page names onto the component palette's popup menu (right click the component palette to see this) It adds support for multi-line component palette (right click the component palette and choose Options to see this) It adds support for hot-tracking on the component palette (right click the component palette and choose Options to see this). Incidentally, this feature isn't particularly obvious, but as you move your mouse over the component palette tabs, the tab caption changes from clWindowText (typically black) to clHighlight (typically blue) It adds support for using buttons instead of tabs on the component palette (right click the component palette and choose Options to see this) It adds a Window menu onto Delphi's menu bar (right click the component palette and choose Options to see this) It allows the speedbar to have non-flat speedbuttons (right click on the speed bar to see this) (Delphi 3 version only) It saves your settings in the Windows registry on Delphi exiting Note: If you choose to use buttons instead of tabs on a Delphi 3 multiline component palette, the IDE window may not be drawn quite large enough (when you highlight a component, some of its icon may not appear in the Delphi IDE window). If you find this, define a new string registry entry: HKEY_CURRENT_USER\Software\Oblong\Archaeopteryx\Tab Height with a value of 19. It defaults to 16. Note: Another possible registry entry to make is as follows. It defaults to "W&indow". If you don't like the Window menu caption, you can change it! In the Delphi 3 version the registry entry is: HKEY_CURRENT_USER\Software\Oblong\Archaeopteryx\Window Menu Caption For the Delphi 4/5 and C++Builder 4/5 version, it is: HKEY_CURRENT_USER\Software\Oblong\Archaeopteryx\4.0\Window Menu Caption Installation Start Delphi 3 or 4 or 5 or C++Builder 4 or 5 Choose Component | Install Packages... Press Add... Locate Archaeopteryx.Dpl or Archaeopteryx.Bpl or Archaeopteryx50.Bpl as appropriate (see descriptions above), select it and press Open Known problems In Delphi 3, if you have a multiline palette and resize the palette with the speedbar/palette splitter, the IDE window will not resize and it will look silly. Turn off multiline before doing this, and turn it back on afterwards. In Delphi 3, if you define a component template and add it to the palette, it defaults to going onto the Templates page (which may not exist before). When this tab is added there is a possibility that a multiline component palette may need an extra line of tabs. Unfortunately Archaeopteryx will not have noticed and so the IDE window will then be too small. Try to remember to turn off multiline before doing this, and turn it back on afterwards. If you install T-Rex, then Archaeopteryx, then uninstall T-Rex, certain IDE options will cause Access violations. You should uninstall IDE extenders in reverse order from which you installed them to avoid this problem, i.e. install T-Rex, then Archaeopteryx, then uninstall Archaeopteryx, and finally uninstall T-Rex Any bugs, please email them to  HYPERLINK "mailto:%62%72%69%61%6E%40%62%6C%6F%6E%67%2E%63%6F%6D" me  Archeopteryx Source Code The complete Archeopteryx source code is in a file called  HYPERLINK "http://www.blong.com/Downloads/DinoSource.zip" DinoSource.zip (18kb). This contains all the Delphi source units along with a package file that will work with Delphi 3 and 4, and another package file that will work with Delphi 5. C++Builder package files are not supplied, but should be easy to manufacture. Just make a new package and add all the Delphi units to it.   HYPERLINK "http://www.blong.com/" \l "Top" Go back to the top of this page   HYPERLINK "http://www.blong.com/Conferences/DCon2001/VCLvsCLX/VCLvsCLX.htm" http://www.blong.com/Conferences/DCon2001/VCLvsCLX/VCLvsCLX.htm VCL versus CLX  HYPERLINK "http://www.blong.com/Conferences/DCon2001/VCLvsCLX/" \l "AboutBrian" Brian Long ( HYPERLINK "http://www.blong.com" \t "_blank" www.blong.com) Table of Contents  HYPERLINK "http://www.blong.com/Conferences/DCon2001/VCLvsCLX/" \l "Introduction" Introduction  HYPERLINK "http://www.blong.com/Conferences/DCon2001/VCLvsCLX/" \l "WhatIsCLX" What Is CLX?  HYPERLINK "http://www.blong.com/Conferences/DCon2001/VCLvsCLX/" \l "BaseCLX" BaseCLX  HYPERLINK "http://www.blong.com/Conferences/DCon2001/VCLvsCLX/" \l "VisualCLX" VisualCLX  HYPERLINK "http://www.blong.com/Conferences/DCon2001/VCLvsCLX/" \l "DataCLX" DataCLX  HYPERLINK "http://www.blong.com/Conferences/DCon2001/VCLvsCLX/" \l "NetCLX" NetCLX  HYPERLINK "http://www.blong.com/Conferences/DCon2001/VCLvsCLX/" \l "WhatsNotInCLX" What's Not In CLX?  HYPERLINK "http://www.blong.com/Conferences/DCon2001/VCLvsCLX/" \l "WhatsNotCrossCompatible" What's Not Cross-Compatible?  HYPERLINK "http://www.blong.com/Conferences/DCon2001/VCLvsCLX/" \l "WhatsNewInCLX" What's New In CLX?  HYPERLINK "http://www.blong.com/Conferences/DCon2001/VCLvsCLX/" \l "VCLvsCLX" How Do The VCL And CLX Libraries Compare?  HYPERLINK "http://www.blong.com/Conferences/DCon2001/VCLvsCLX/" \l "Styles" Styles  HYPERLINK "http://www.blong.com/Conferences/DCon2001/VCLvsCLX/" \l "TheLifeAndDeathOfAControl" The Life And Death Of A Control  HYPERLINK "http://www.blong.com/Conferences/DCon2001/VCLvsCLX/" \l "WindowsMsgsVsQtEvents" Windows Messages vs. Qt Events  HYPERLINK "http://www.blong.com/Conferences/DCon2001/VCLvsCLX/" \l "OverridingVirtualHandler" Overriding The Virtual Handler In A New Component   HYPERLINK "http://www.blong.com/Conferences/DCon2001/VCLvsCLX/" \l "OverridingVCLVirtualHandler" VCL  HYPERLINK "http://www.blong.com/Conferences/DCon2001/VCLvsCLX/" \l "OverridingCLXVirtualHandler" CLX  HYPERLINK "http://www.blong.com/Conferences/DCon2001/VCLvsCLX/" \l "InjectingNewHandler" Injecting A New Handler In Another Component   HYPERLINK "http://www.blong.com/Conferences/DCon2001/VCLvsCLX/" \l "InjectingNewVCLHandler" VCL  HYPERLINK "http://www.blong.com/Conferences/DCon2001/VCLvsCLX/" \l "InjectingNewCLXHandler" CLX  HYPERLINK "http://www.blong.com/Conferences/DCon2001/VCLvsCLX/" \l "NotificationsVsSignals" Windows Notifications vs Qt Signals  HYPERLINK "http://www.blong.com/Conferences/DCon2001/VCLvsCLX/" \l "NotificationsVsSignalsVCL" VCL  HYPERLINK "http://www.blong.com/Conferences/DCon2001/VCLvsCLX/" \l "NotificationsVsSignalsCLX" CLX  HYPERLINK "http://www.blong.com/Conferences/DCon2001/VCLvsCLX/" \l "Summary" Summary  HYPERLINK "http://www.blong.com/Conferences/DCon2001/VCLvsCLX/" \l "FutherReading" Further Reading  HYPERLINK "http://www.blong.com/Conferences/DCon2001/VCLvsCLX/" \l "AboutBrian" About Brian Long   Introduction This paper will look at the new CLX library (pronounced clicks) that ships with all versions of Kylix and also with Delphi 6 and later. Delphi developers are familiar with the VCL, the Windows-only component library. During this session, we will look at how the VCL and CLX libraries compare, and also how they differ. Clearly, with the two libraries being as large as they are, we can not get a thorough and complete comparison, but we will focus on some of the more important aspects during this session. You can find out more about this subject through the references in the  HYPERLINK "http://www.blong.com/Conferences/DCon2001/VCLvsCLX/" \l "FutherReading" Further Reading section at the end of this paper.  HYPERLINK "http://www.blong.com/Conferences/DCon2001/VCLvsCLX/VCLvsCLX.zip" Click here to download the files associated with this paper. What Is CLX? CLX is Borland's first cross-platform class library, designed for the release of Kylix 1 in March 2001. It was introduced after analysis of the VCL (used in Delphi 1 through to 5, and also C++Builder 1 through to 5) indicated that a straight port would be very difficult due to the VCL's inherent marriage to the Windows API. Rather than struggle trying to get the VCL in a shape where it could be ported to another platform, they decided it would be most advantageous to start again, from scratch. The result was the CLX library, which in many respects works just like the VCL, but also in many respects is very different from its Windows-only counterpart. If you want to write code for Windows only, you develop applications using the VCL. If you want to write applications whose source code can be compiled into either a Windows application or a Linux application, you develop using CLX. CLX is truly a source-level, cross-platform class library. When work first started on CLX, Delphi 5 and C++Builder 5 were already out. Consequently, the model for CLX 1 (which was to be shipped first with Kylix 1) was VCL 5. As many components, routines and features from VCL 5 have been incorporated into CLX 1 as possible, making the development experience in Kylix 1 very similar to that in Delphi 5. Obviously, non-portable features such as COM, ActiveX and the like have no place in CLX, but that notwithstanding, the CLX library is still a rich development library. CLX first shipped with Kylix 1, and is also supplied with Delphi 6 (and later). Delphi 6 has VCL 6 and CLX 1 supplied with it. This can sometimes be a bit confusing, as VCL 6 has many new features that are not present in CLX 1 (these will be added, where possible, in CLX 2). CLX has been subdivided into four separate parts, as described below. BaseCLX This term describes the basic run-time library along with a few other key units that were historically considered part of the VCL. Table 1 shows the common units that make up BaseCLX. However, on both Windows and Linux, BaseCLX also contains the local API import units (Libc, Xlib, KernelDefs, etc. on Linux and Windows, ShellApi, CommCtrl, etc. on Windows). You can see the Kylix BaseCLX package in Figure 1). Table 1: The main BaseCLX units Unit nameDescriptionSystemCore RTL unit providing basic operational routines and TObjectSysInitCore RTL unit that implements startup and shutdown codeSysUtilsCommon utility routines and exception classesSysConstString constants used in SysUtilsRTLConstsString constants used in various RTL unitsTypesCommon type definitionsVariantsPortable Variant implementationVarUtilsPlatform-neutral Variant support routinesMathMathematical routinesDateUtilsDate manipulation utilities (in addition to those found in SysUtils)TypInfoRTTI support routines and data structuresClassesBasic component definitions along with streaming supportIniFilesSupport for INI file manipulationSyncObjsSynchronisation objects (event and critical section)ContnrsContainer classes, such as stacks and queuesMasksMask class for comparing strings containing wildcards to a file maskMaskUtilsMask manipulation routinesHelpIntfsInterfaces for extending the help system (in your apps and in the IDE)Figure 1: The Kylix BaseCLX package  INCLUDEPICTURE "http://www.blong.com/Conferences/DCon2001/VCLvsCLX/BaseCLX.gif" \* MERGEFORMATINET  As you can imagine, with the RTL files in BaseCLX being common to Kylix and Delphi, a fair amount of conditional compilation is involved to cater for API differences. This takes the form shown in Listing 1. Listing 1: Conditional compilation for Linux and Windows uses {$IFDEF MSWINDOWS} Windows, {$ENDIF} {$IFDEF LINUX} Types, Libc, {$ENDIF} SysConst; The first thing to notice is the use of the new MSWINDOWS symbol, defined in Delphi 6 onwards when compiling for any Windows platform (Win32, Win64 or whatever). This symbol does not exist in earlier versions of Delphi, but it is easy enough to define yourself. The second thing to notice is that two separate $IFDEF directives are being used. It is not safe to check for LINUX and, if it is not set, assume you are compiling for Windows. Similarly it is not safe to check for MSWINDOWS and, if it is not set, assume you are compiling for Linux. Other potential platforms may be introduced in the future making such assumptions invalid. As well as all the conditional code, another thing to notice in the case of both CLX and the VCL in Delphi 6 is that there are no longer separate assembly files that need assembling and linking into the System unit. All of these files have been turned into inline assembly code in the required places. In some cases, the inline assembly code has also been translated into pure Pascal code. This is probably to allow easier debugging for those not so au fait with assembly programming. Listing 2 shows an example of the bilingual representation of an RTL routine (UpCase in this case). Note that the PUREPASCAL symbol is not defined, but you can readily rebuild the RTL using the Borland-supplied make file, defining any symbols you choose. Listing 2: Pure Pascal translations of older inline assembler available function UpCase( ch : Char ) : Char; {$IFDEF PUREPASCAL} begin Result := ch; case Result of 'a'..'z': Dec(Result, Ord('a') - Ord('A')); end; end; {$ELSE} asm { ->AL Character } { <- AL Result } CMP AL,'a' JB @@exit CMP AL,'z' JA @@exit SUB AL,'a' - 'A' @@exit: end; {$ENDIF} VisualCLX This part of CLX represents the visual components that would reside in the TWinControl hierarchy in the VCL. The VCL makes use of natively implemented Windows controls and provides classes that turn those controls into components. Any component representing a control that is implemented by Windows (and therefore has a window handle) will be inherited at some point from TWinControl. However, this approach only works where Windows controls exist, which means the VCL only works on Windows platforms. The VisualCLX framework is a set of classes that represent visual controls but must work where possible on both Microsoft Windows and in X Windows in Linux (these are the currently supported platforms, where both must be running on Intel-compatible chips). The controls represented by the VisualCLX components are implemented by a C++ class library called Qt (produced cute), from a Norwegian development company called Trolltech. The Qt library has a strong presence on Linux, where (for example) the people who develop the popular KDE desktop environment use it. Qt implements a number of controls for X Windows applications, many of which mirror those available in Windows (X Windows implements no controls of its own). Qt is also available on Windows where the same classes allow C++ applications to be ported between Linux and Windows reasonably easily. Qt is an example of a control library, one of many that exist (others include GTK+ and Athena). These control libraries are generally referred to as widget libraries, where a widget is the common Linux term for a control (from a contraction of window gadget). All controls in VisualCLX are made from Qt widgets, and consequently, the equivalent of the VCL TWinControl class is called TWidgetControl (although the type TWinControl is defined to be the same as TWidgetControl). Qt is a C++ class library and, because of differences in C++ and Object Pascal implementation details, an Object Pascal program cannot directly manipulate Qt widgets. Instead, VisualCLX makes use of an additional library, typically referred to as the Qt interface library. This library is also written in C++, but it exports all the Qt functionality in a manner that is accessible to Object Pascal code. The import unit for this interface library is called Qt.pas and is referred to as the CLXDisplay API. In this unit you can find all the Qt functionality from the original C++ classes exposed as flat methods (a method of a class that is declared as a standalone subroutine). This means that rather than being declared as classes, the Qt widget methods are all imported as functions. However, since at the C++ side they are indeed classes, almost every flat method takes one extra parameter, which is the reference to the Qt widget. In a normal Object Pascal application, you call methods via object references, for example: Button1.SetBounds(10, 10, 75, 25); When a normal method is turned into a flat method, the object reference is passed as the first parameter so the method code knows which instance it should be working against. Here is a fictitious example flat method, which is equivalent to the method just used: TButton_SetBounds(Button1, 10, 10, 75, 25); In the made-up examples shown here, there is little point using the flat method, as an object reference like Button1 always allows you access to its members. In the real case of the CLXDisplay API, however, the object references cannot be used in this way (which is why the flat methods are provided in the first place). Any Qt constructor (which again is declared as a flat method) returns a reference to the C++ Qt widget, but this cannot be used as such in a CLX application. The flat constructor returns a pointer (which is what an object reference is), which is usable as the first parameter to appropriate flat methods, but not for direct access to the pertinent methods. Such a pointer is referred to as an opaque reference to a Qt widget. Rather than leave these opaque references as raw pointers, CLX defines an Object Pascal class hierarchy to mirror the Qt hierarchy, but which defines no methods or properties at all for any of its classes. These classes are representative only. They allow what would otherwise be raw pointers to be defined of appropriate types in a hierarchy, and thereby allow the compiler to validate the use of these values. The flat constructors return values defined in terms of classes from this hierarchy. Again, the returned value is of little use on its own, but is useful when passed to an appropriate flat method. It is quite common for the term handle to be used for a value that has a use in an application, but has no real meaning to the programmer. Take for example a window handle, or a file handle; these mean nothing to the programmer, other than a means to uniquely identify a given window or a given open file. Opaque Qt references, when defined in terms of classes in the aforementioned Object Pascal class hierarchy (a portion of which can be seen in Listing 3) are referred to as Qt widget handles, or simple Qt handles for similar reasons. Listing 3: Part of the Object Pascal Qt handle hierarchy type QtH = class(TObject) end; QObjectH = class(QtH) end; QApplicationH = class(QObjectH) end; QClxApplicationH = class(QApplicationH) end; QWidgetH = class(QObjectH) end; QOpenWidgetH = class(QWidgetH); QButtonH = class(QWidgetH) end; QPushButtonH = class(QButtonH) end; QClxBitBtnH = class(QPushButtonH) end; QComboBoxH = class(QWidgetH) end; QOpenComboBoxH = class(QComboBoxH) end; QFrameH = class(QWidgetH) end; QTableViewH = class(QFrameH) end; QMultiLineEditH = class(QTableViewH) end; You can see that the flat methods make use of these handle types by looking at some of their declarations (see Listing 4). The flat constructor for the QPushButton widget returns a QPushButton handle (defined as type QPushButtonH). All the other flat methods require a QPushButton handle as their first argument. Listing 4: Some of the flat methods of QButton function QPushButton_create(parent: QWidgetH; name: PAnsiChar): QPushButtonH; overload; cdecl; function QPushButton_create(text: PWideString; parent: QWidgetH; name: PAnsiChar): QPushButtonH; overload; cdecl; procedure QPushButton_destroy(handle: QPushButtonH); cdecl; procedure QPushButton_setGeometry(handle: QPushButtonH; x: Integer; y: Integer; w: Integer; h: Integer); overload; cdecl; procedure QPushButton_setGeometry(handle: QPushButtonH; p1: PRect); overload; cdecl; We will come back to the CLXDisplay API  HYPERLINK "http://www.blong.com/Conferences/DCon2001/VCLvsCLX/" \l "InjectingNewCLXHandler" later as we see how to customise CLX components. Before moving on though, Listing 5 shows how you can create, manipulate and destroy a Qt widget solely using Qt handles and Qt flat methods. Notice that the QPushButton constructor is called, followed by a QPushButton method. The next call is to a QButton method that QPushButton inherits and the last call is to the QPushButton destructor. Listing 5: Simple manipulation of a Qt widget using the CLXDisplay API uses Qt, QTypes; ... var Btn: QPushButtonH; ... procedure TForm1.FormCreate(Sender: TObject); var Msg: TCaption; begin Btn := QPushButton_create(Handle, PChar('Btn')); QPushButton_setGeometry(Btn, 10, 10, 75, 25); Msg := 'Press me'; QButton_setText(Btn, PWideString(@Msg)); end; procedure TForm1.FormDestroy(Sender: TObject); begin QPushButton_destroy(Btn); end; Of course you would normally have no need to do this, as most commonly required widgets are already wrapped up in CLX component classes. However, familiarity with the mechanics of interacting with Qt is useful to get under your belt. Also useful is to note that in the VCL, a visual component's Handle property is a window handle. In a Visual CLX component, the Handle property is a Qt widget handle. DataCLX Since the BDE is not going to be ported anywhere from Windows, we need to understand how a cross-platform library like CLX can provide data access. The answer to this question is in dbExpress. dbExpress is designed to be a replacement for the BDE, or ADO data accessing technologies, which are Windows-specific. It is a cross-platform, database-independent layer that provides methods for dynamic SQL processing. It defines a common interface for accessing a variety of SQL servers (InterBase, MySQL, Oracle and DB2 in the initial release). Legacy data file formats such as Paradox and dBASE are not supported. For each supported server, dbExpress provides a driver, which acts as an independent library implementing the common dbExpress interfaces for processing queries and stored procedures. dbExpress drivers are available for both the Windows platform (as dynamic-link libraries) and the Linux platform (as shared object files). dbExpress has been designed from the outset to be fast, lightweight and easy to deploy. As such, it does very little data processing of its own, but mainly acts as a thin wrapper around the database server's client-side software. It provides the advantages of a common API without the overhead of a more elaborate database engine such as the BDE. For example, dbExpress drivers return only unidirectional cursors and perform no data or metadata caching. By keeping the core runtime data-access layer thin and simple, dbExpress provides high performance database connectivity that can be easily adapted to new data sources. The dbExpress interfaces defined in the DBXpress unit are ISQLDriver, ISQLConnection, ISQLCommand, ISQLCursor and ISQLMetaData (all of which are documented in the online help). Note that it is expected that the InterBase and MySQL dbExpress drivers are to have their source code released to help stimulate the 3rd party driver market. As with the other data access components, there is a dedicated connection component, TSQLConnection. This allows you to specify what type of database you are connecting to and allows the driver details to be set up. Driver and connection details are stored in very simple text files (Windows INI files) making setup much easier than with the BDE, for example. Some TDataSet descendant classes are provided that map directly onto the dbExpress interfaces: TSQLDataSet, TSQLQuery, TSQLStoredProc and TSQLTable. Since these use unidirectional cursors, data-aware controls will not co-operate with these dataset components. However this problem can be overcome if data aware controls are important to you. On top of the core interfaces, application developers can create a layer for caching data and thereby provide forward and backward scrolling on the result set. For example, components such as a client dataset can provide the support for caching, scrolling, indexing, and filtering dbExpress result sets. TSQLClientDataSet is a provided client dataset descendant that combines a TSQLDataSet and TDataSetProvider. Whilst the initial release in Kylix operated solely on the basis of external driver files (shared objects), the Windows version allows the drivers to be compiled into the application, reducing the deployment complexity. So when developing a Windows-based dbExpress application, you can either link to the DLL driver (dbexpint.dll, dbexpora.dll, dbexpmys.dll, or dbexpdb2.dll) or alternatively you can link the driver into your application by using the relevant compiled unit (dbexptint.dcu, dbexpora.dcu, dbexpmys.dcu, or dbexpdb2.dcu). Very much as with other TDataSet descendants, these components are straightforward to use. If you use the basic classes (TSQLDataSet, TSQLQuery, TSQLStoredProc and TSQLTable) you will have to dispense with data aware controls and display any necessary data yourself in normal controls, due to their unidirectional nature. If you are happy to have a bit of caching done for you and you use the TSQLClientDataSet component, then you can use data aware controls as you might with BDE or ADO controls when using the VCL (see Figure 2). Figure 2: Using the dbExpress wrapper component to make use of a data aware control  INCLUDEPICTURE "http://www.blong.com/Conferences/DCon2001/VCLvsCLX/dbExpress.gif" \* MERGEFORMATINET  NetCLX The NetCLX portion of the CLX library seems to be the part that has changed least. Apart from the differences of being able to support ISAPI, NSAPI and WinCGI on Windows platforms, the WebBroker principles from the VCL transfer across perfectly well. Of course database-driven Web server applications must use dbExpress instead of BDE or ADO components but, other than that, Web-related things are very much the same as they are in Delphi 5 VCL, with the addition of support for Apache Web server applications and shared modules. NetCLX also includes the Internet Direct suite of components (known as Indy). These are freeware components that work in Delphi, C++Builder and Kylix, and work with both the VCL and CLX libraries (see Figure 3). Figure 3: Some of the Indy Server components  INCLUDEPICTURE "http://www.blong.com/Conferences/DCon2001/VCLvsCLX/Indy.png" \* MERGEFORMATINET  What's Not In CLX There are many things that we are used to from writing VCL applications that are simply not present in CLX. This may be due to them relying on platform-specific features, and so not being appropriate for a cross-platform library. It may also be that the Borland developers have either not had the chance to implement the features yet, or have decided the features are not valuable enough to warrant migrating. Here is a list of the missing features: Any COM-based support such as ActiveX, Automation and COM are not in CLX, since these are specific Microsoft technologies that are not present outside of Microsoft Windows. This includes all the components on the Servers page of the Component Palette. The DDE components rely on a Microsoft Windows feature and are not in CLX. The BDE will not be ported to Linux, so the associated components (TDatabase, TTable, TQuery, and TStoredProc) are not in CLX. Also, associated BDE tools such as the BDE Data Dictionary, SQL Explorer and SQL Monitor will not be found on Linux. You should use the new cross-platform  HYPERLINK "http://www.blong.com/Conferences/DCon2001/VCLvsCLX/" \l "DataCLX" dbExpress components in place of the BDE data access components (note that dbExpress includes a TSQLMonitor component). The ADOExpress components (or dbGo components as they were renamed to in the Delphi 6 VCL) will not be moved to Linux, and so are not part of CLX. This is because ADO is a Microsoft COM-based technology. Use  HYPERLINK "http://www.blong.com/Conferences/DCon2001/VCLvsCLX/" \l "DataCLX" dbExpress instead. The Windows 3.1 compatibility components (on the Win 3.1 page of the Component Palette) are not in CLX. The Decision Cube components are not in CLX. The QuickReports components are not in CLX (unless their author comes up with the goods). The NetManage Internet components are not in CLX. Instead, you should use the Indy ( HYPERLINK "http://www.blong.com/Conferences/DCon2001/VCLvsCLX/" \l "NetCLX" Internet Direct) components, which work in both the VCL and in CLX. Support for externally generated Windows messages is not in CLX. You will need to use the  HYPERLINK "http://www.blong.com/Conferences/DCon2001/VCLvsCLX/" \l "NotificationsVsSignals" Qt event/signal model instead. All the VCL message handler methods have been turned into dynamic methods instead; for example the WMMouseMove message handling method has become the MouseMove dynamic method. Support for drag and dock in CLX applications is currently missing (this is hoped to be added in a later version of CLX). The TApplicationEvents component is not in CLX. Bi-directional properties (such as the BidiMode property) for right-to-left text output or input are not in CLX. IME support (Input Method Editor) is not in CLX. Asian locale support is not in CLX. What's Not Cross-Compatible? When writing CLX applications on the Windows platform, there will be a certain amount of the BaseCLX support and also some components which will work in a Windows CLX application, but will not port across to Linux. The same is true in the other direction as well. Some features available in a Kylix CLX application will not compile in a Windows CLX application. When writing cross-platform applications you should be aware of these issues and try and steer clear of them wherever possible. Here is a list of some of the important cases: Win32 API calls from the Windows import units and Linux API calls from the Linux import units should be used with care, perhaps in conjunction with some conditional compilation. Occasional Windows API routines have been made available on Linux through an appropriate implementation in an RTL unit, for example LoadLibrary, FreeLibrary, GetProcAddress, GetModuleHandle, GetModuleName and Sleep. Windows support routines such as Win32Check, RaiseLastWin32Error and OleCheck. Note that RaiseLastWin32Error can be replaced with the cross-platform RaiseLastOSError routine instead. Microsoft Extensions such as MAPI should be avoided where possible. Instead, use the Indy components that are supplied with Kylix and Delphi (version 6 and later). UNC filename support is not available on Linux, so for example, the ExpandUNCFileName routine will not be present. Assumptions about the file system will cause problems. File names are case sensitive on Linux, but not on Windows, for a start. Also, path lists are separated by a semicolon on Windows and a colon on Linux, directories in a path are separated by a backslash on Windows and a forward slash on Linux, and there is no concept of a drive letter on Linux. If you use the supplied platform-dependent variables (PathSep and PathDelim) in your code you can overcome some of these issues. There are also various BaseCLX routines to help with these issues: IsPathDelimiter, IncludeTrailingPathDelimiter, IncludeTrailingBackslash, ExcludeTrailingPathDelimiter and ExcludeTrailingBackslash. WebBroker support works well in CLX, but the only cross-platform options are CGI and Apache shared module. WinCGI, ISAPI and NSAPI are not supported on Linux. MIDAS connection components based on IDispatch (such as TDCOMConnection) are not available on Linux. Accessing the registry with TRegistry or TRegIniFile will not work on Linux, as the registry is a Windows concept. Third party components may not be ported across to Linux, depending on the abilities or expectations of the original authors. This is an important fact as many applications use third party components. Safecall exceptions will not occur on Linux, as they are designed to represent exceptions that occur in COM servers. References to the safecall calling convention will be mapped onto cdecl. The stdcall calling convention is mapped onto cdecl on Linux. What's New In CLX? Most of the new things in CLX have already been mentioned to some degree or other. Here is a summary list of them:  HYPERLINK "http://www.blong.com/Conferences/DCon2001/VCLvsCLX/" \l "DataCLX" dbExpress, the thin, fast, cross platform data access layer The use of Qt for all the  HYPERLINK "http://www.blong.com/Conferences/DCon2001/VCLvsCLX/" \l "VisualCLX" visual controls, and the consequent requirement of the Qt interface library Apache support in  HYPERLINK "http://www.blong.com/Conferences/DCon2001/VCLvsCLX/" \l "NetCLX" WebBroker  HYPERLINK "http://www.blong.com/Conferences/DCon2001/VCLvsCLX/" \l "NetCLX" Internet Direct component set (Indy) Portable Variant implementation (Variants are supported on Linux) Custom Variant data handler. As well as handling the normal data types, Variants can be programmed to understand new data types as well  HYPERLINK "http://www.blong.com/Conferences/DCon2001/VCLvsCLX/" \l "Styles" Styles Form files have an .xfm extension in Kylix (Delphi uses .dfm). This allows conditional compilation to decide which one to link in, allowing different form files to be used on either platform. How Do The VCL and CLX Libraries Compare? The CLX library was designed from the outset to be as similar to the VCL as possible. In general, this principle was upheld, but where appropriate, differences have been introduced. These differences reflect the fact that CLX is not Windows-dependent (in fact in some cases, the changes reflect the fact that it is dependent on the Qt widget library). Here are some key points. Most component names are the same, with the exception of TWinControl, which is called TWidgetControl in CLX. That said, the class TWinControl does exist in CLX; it is provided to help source code compatibility and is defined to be the same as TWidgetControl. The class hierarchy is mostly the same, with the exception of TWinControl becoming TWidgetControl, and TScrollingWinControl, which is called TScrollingWidget. Most property names are the same Windows message handlers can still be declared, but messages are not delivered from outside a CLX application. The only way message handlers will be triggered is by a message being sent from somewhere within the application to a control in the same application. Most VCL Windows message handlers have been turned into dynamic methods. The VisualCLX unit names are much the same as the VCL unit names, but have a Q prefix letter. So StdCtrls becomes QStdCtrls, and so on. The NetCLX, DataCLX and BaseCLX units are the same as the VCL units. The Windows concept of owner drawn controls is still there (for example TListBox has an OnDrawItem event). However, in general, the appearance of controls is customised using styles. Variants are a Windows feature. To allow Variants to be used in CLX cross-platform applications, Borland have provided a platform-independent implementation of Variants. The main Variant support unit is called Variants, and all the Variant support routines are in the VarUtils unit. Linux has no registry, but instead uses text files for storing information. You can keep code portable by using TMemIniFile in CLX applications, which allows buffered access to an INI file. Windows CLX applications can also use TMemIniFile, or if you prefer to use the registry, you can use TRegistryIniFile or TRegIniFile, with a little conditional compilation. Some properties are missing in CLX, due to the Qt equivalent of Windows controls not supporting the full Windows control feature set. An example would be the DisplayRect property of TTabControl, which is not present in CLX. Styles Whilst you can change the styles of controls on an individual basis, the starting point will be the default application style. The Application object has a Style property, which refers to a TApplicationStyle object. TApplicationStyle inherits from TStyle, both of which are defined in the QStyle unit. There are a number of properties that affect individual control appearances. For example, ButtonShift dictates how many pixels a button's image moves when it is pressed down, and CheckSize controls how large a checkmark will be. However the most interesting property is DefaultStyle, which can be given any value from the TDefaultStyle enumerated type (see Listing 6). Listing 6: The available default styles TDefaultStyle = (dsWindows, dsMotif, dsMotifPlus, dsCDE, dsQtSGI, dsPlatinum, dsSystemDefault); A simple project called AppStyle.dpr accompanies this paper; it has a number of controls on it and a menu that allows you to choose any of the available styles (visible in Figure 4). Figure 5 shows the application sporting the Platinum style and Figure 6 shows it with the SGI style. When you unzip the accompanying files, there is a VCL and a CLX directory. This project is in the CLX directory. Figure 4: Choosing a new style  INCLUDEPICTURE "http://www.blong.com/Conferences/DCon2001/VCLvsCLX/StyleWin.gif" \* MERGEFORMATINET  Figure 5: The Platinum style  INCLUDEPICTURE "http://www.blong.com/Conferences/DCon2001/VCLvsCLX/StylePlatinum.gif" \* MERGEFORMATINET  Figure 6: The SGI style  INCLUDEPICTURE "http://www.blong.com/Conferences/DCon2001/VCLvsCLX/StyleQtSGI.gif" \* MERGEFORMATINET  As well as these properties, the style object has a multitude of events that allow you to customise various aspects of different types of controls. Listing 7 shows them all. Note that the OnPolish event is the only event added by TApplicationStyle (all the others are inherited from TStyle). OnPolish can be used to tweak the Application object properties before any of the painting starts. Listing 7: The mass of events on offer by a TApplicationStyle object OnPolish AfterDrawButton AfterDrawItem AfterDrawMenuItem BeforeDrawButton BeforeDrawItem BeforeDrawMenuItem ButtonRect ComboButtonFocusRect ComboButtonRect DrawArrow DrawButtonFrame DrawButtonLabel DrawButtonMask DrawCheck DrawCheckMask DrawComboButton DrawComboButtonMask DrawFocusRect DrawFrame DrawHeaderSection DrawHint DrawMenuCheck DrawMenuFrame DrawRadio DrawRadioMask DrawScrollBar DrawSplitter DrawTab DrawTabMask DrawTrackBar DrawTrackBarGroove DrawTrackBarGrooveMask DrawTrackBarMask ExtraMenuItemWidth GetItemRect HeaderSectionRect MenuItemHeight OnChange ScrollBarMetrics SubmenuIndicatorWidth TabMetrics Individual widgets have their own style objects; their Style property returns a TWidgetStyle object. TWidgetStyle also adds an OnPolish event to allow widget properties to be set appropriately before any painting begins. The Life And Death Of A Control Some of the key methods in the life and death of a VCL windowed control (TWinControl descendant) are different in a VisualCLX component. Let's see what's changed. When a VCL control is displayed, a window handle is needed and so the virtual CreateHandle method is called. CreateHandle calls the virtual CreateWnd method to get a window handle and then sets the control's z-order. CreateWnd sets things up for the Windows API call that will ultimately be called. It sets up the window creation parameters through another virtual method, CreateParams, which itself may well call CreateSubClass to make use of an existing Windows control class. After CreateParams returns and various things have been checked, the virtual CreateWindowHandle method is called to finish off the job. CreateWindowHandle calls the Windows API CreateWindowEx to create the underlying control and assigns the resultant window handle to the Handle property. At the other end of the control's life, when it needs to be disposed of, the DestroyHandle virtual method is called. This calls DestroyHandle for any child controls and then calls the virtual DestroyWnd method. DestroyWnd is intended to destroy the underlying windowed control and it does so by calling the virtual DestroyWindowHandle method. DestroyWindowHandle finishes the job by calling the Windows API DestroyWindow. In CLX, the corresponding TWidgetControl class also has a chain of virtual methods responsible for setting up and pulling down an underlying Qt widget. When the control is required, the CreateHandle method is called, however unlike in the VCL, CreateHandle is not virtual. CreateHandle calls the virtual CreateWidget method first, which creates the underlying widget, storing the widget handle in the Handle property. It then creates an appropriate hook object for the widget and assigns its handle to the Hooks property, so that the component can react to interesting things that happen to the widget. After CreateWidget, CreateHandle then calls the virtual InitWidget, which initialises the freshly created widget settings. It then goes on to call HookEvents, which uses the hook object to connect Object Pascal methods to the widget signals. When the widget is no longer required the non-virtual DestroyHandle method is called. This calls the virtual DestroyWidget which firstly calls the dynamic WidgetDestroyed method (which destroys the hook object) and then proceeds to destroy the widget itself. Table 2 shows a comparison of these call chains. Table 2: A comparison of creating and destroying controls in VCL and CLX VCLCLXControl/widget creationCreateHandle CreateWnd CreateParams CreateSubClass CreateWindowHandle CreateWindowExCreateHandle CreateWidget widget constructor InitWidget HookEventsControl/widget destructionDestroyHandle DestroyWnd DestroyWindowHandle DestroyWindowDestroyHandle DestroyWidget WidgetDestroyed widget destructorWindows Messages vs Qt Events In this section we will see how to intercept the miscellaneous system level messages that are constantly delivered to the underlying Windows controls and Qt widgets. Whilst this might appear to be a section dedicated to component writers, it is not. It is very common for application developers to handle certain messages that are delivered to their forms, or to customise the behaviour of some components by having them react differently to certain stimuli. CLX applications have the potential of running under Microsoft Windows and X Windows (and maybe other platforms in the future). Windows messages are specific to the Microsoft Windows platforms, and so to promote cross-platform capabilities, CLX applications do not propagate Windows messages through to your component message handlers. Clearly, as Windows programmers, we will need to spend some time acclimatising to this lack of Windows messages. More specifically, we should learn what mechanism is used by Qt in lieu of Windows messages. We need to understand what cross-platform solution is used by Qt to indicate that certain system events have happened (like a mouse being pressed, released or moved, or a key being pressed or released). In a CLX application, the equivalent of a Windows message is a Qt event. Whilst a Windows message is typically represented by a record (such as TMessage) containing the message ID, and the two numeric values that accompany it, Qt events are represented by objects. There is a base QEvent class (and a corresponding QEventH handle class) which has numerous descendants such as QKeyEvent and QMouseEvent. When a CLX program is running on the Windows platform, these Windows messages are picked up by the Qt event loop and turned into Qt events and sent on their way to the appropriate Qt widgets. Similarly, when running on X Windows, the low level X events are picked up by the Qt event loop and turned into Qt events before being passed to the appropriate Qt widgets. If you were writing a VCL component (even just inheriting an existing component to make a small modification, or inheriting from a form), you could pick up Windows messages either in dedicated Windows message handling methods, or in an overridden version of the window procedure method, WndProc. WndProc is fed every message directed at the component, allowing you to perform appropriate actions in response to them if needed. The WndProc signature looks like this: procedure WndProc(var Message: TMessage); virtual; In a CLX application, Qt events do not have the equivalent of message handling methods, but they are all fed to a virtual method. However, the virtual method is called an event filter and has this signature: function EventFilter(Sender: QObjectH; Event: QEventH): Boolean; virtual; You override this in a CLX component and it receives all the events that are destined to reach the underlying Qt widget. The Sender parameter is the underlying Qt widget handle (the same as the value of your component's Handle property) and the Event parameter is a handle to the event object. You can find out the type of the event by passing the event handle to the QEvent flat method QEvent_type. This returns a value from the QEventType enumerated type, which includes values such as QEventType_MouseButtonPress, QEventType_MouseButtonRelease, QEventType_MouseMove, QEventType_KeyPress and QEventType_KeyRelease. Once you know the type of the event, you can typecast the event handle into one of the inherited handle types appropriate for the event, such as QMouseEventH or QKeyEventH. Each of these inherited classes has more flat methods. For example, the mouse event object has methods to find the current mouse co-ordinates and the key event object has a method for returning the pressed key. Overriding The Virtual Handler In A New Component VCL To give a generic example of hooking a VCL control's window procedure, and what it picks up, I've written a new component called TButtonEx (a simple descendant of TButton). This class overrides WndProc and, for each message that arrives, it passes the message record along to a custom event call OnMessage. There's also a sample application in the VCL directory of the files that accompany this paper. The project is called WindowProcTrace.dpr and has a TButtonEx component placed on its form. An event handler for its OnMessage event adds a descriptive message into a list view for each message that arrives. To run the program you will need to add the component unit, ButtonEx, into a design-time package and install it. Figure 7 shows the program running. You can see the list view has information on a whole series of messages that were delivered to the button. You can also see a check box that enables or disables the message trace. Figure 7: A WndProc method that traces messages  INCLUDEPICTURE "http://www.blong.com/Conferences/DCon2001/VCLvsCLX/MsgTrace.gif" \* MERGEFORMATINET  The window procedure method itself is quite straightforward (as shown in Listing 8). Note that if you do not wish for some messages to reach the button, then you can simply omit the call to the inherited window procedure for that message. Listing 8: An overridden VCL WndProc method type TMessageEvent = procedure(Sender: TComponent; var Msg: TMessage) of object; TButtonEx = class(TButton) private FOnMessage: TMessageEvent; protected procedure WndProc(var Message: TMessage); override; published property OnMessage: TMessageEvent read FOnMessage write FOnMessage; end; ... procedure TButtonEx.WndProc(var Message: TMessage); begin if Assigned(OnMessage) then OnMessage(Self, Message); //Do not call inherited window proc if you want to hide the message inherited; end; The actual event handler in the form unit is also quite simple. It calls a helper routine that looks at the message and writes the corresponding constant name, as well as the accompanying numeric values and the time, in the list view control. CLX The CLX directory in the accompanying files has an equivalent component and sample project that shows the CLX approach to this problem. The button descendant overrides the EventFilter method (as shown in Listing 9) and similarly passes the event handle to an event, simply so it is easy for the sample project to add descriptive information to the list view control. Note that if you do not wish for some events to reach the button, then you can make the event filter return True. Listing 9: An overridden CLX EventFilter method type TQtEvent = procedure(Sender: TComponent; Widget: QObjectH; Event: QEventH) of object; TButtonEx = class(TButton) private FOnQtEvent: TQtEvent; protected function EventFilter(Sender: QObjectH; Event: QEventH): Boolean; override; published property OnQtEvent: TQtEvent read FOnQtEvent write FOnQtEvent; end; ... function TButtonEx.EventFilter(Sender: QObjectH; Event: QEventH): Boolean; begin if Assigned(OnQtEvent) then OnQtEvent(Self, Sender, Event); //Return True if you want to hide the event Result := inherited EventFilter(Sender, Event) end; You can see the program, EventFilterTrace.dpr, in action in Figure 8. Figure 8: An event filter that traces Qt events  INCLUDEPICTURE "http://www.blong.com/Conferences/DCon2001/VCLvsCLX/EventTrace.gif" \* MERGEFORMATINET  Injecting A New Handler In Another Component Overriding the virtual WndProc or EventFilter method is fine if you are actually inheriting a new class. However, what if you want to intercept messages or events of an existing object? How do you intercept the window procedure or event filter without overriding the virtual methods? VCL In the VCL, this is catered for with the WindowProc property. WindowProc points to the control's window procedure, and it defaults to pointing at WndProc. Any other class can define a suitable method and assign it to WindowProc in order to intercept all messages. The idea is to look at the message and, if it one you are after, you respond to it accordingly. If you wish to let the message continue on its path to the control, then you must call the original window procedure that you will have saved before setting up the new one. If you want to hide the message, do not call the original window procedure. A sample VCL project is supplied with this paper, called WindowProcHook.dpr. This project looks much like the previous projects, but this time the check box either installs the new window procedure or restores the original one. You can see the main code from the program in Listing 10. The window procedure is set or restored by the SetNewBtnWndProc method, which takes a Boolean parameter to indicate what to do. If a new window procedure is being set, the old one is stored first in a private data field (FOldBtnWndProc), otherwise it is restored from this data field (assuming a valid value is found). As you can see, the replacement window procedure does little other than add a descriptive entry into the list view before calling the original window procedure. The program looks pretty similar to Figure 7 when running. Listing 10: Intercepting a button's window procedure type TForm1 = class(TForm) ... private FOldBtnWndProc: TWndMethod; procedure NewBtnWndProc(var Message: TMessage); public procedure SetNewBtnWndProc(Enable: Boolean); end; ... procedure TForm1.chkWndProcHookedClick(Sender: TObject); begin SetNewBtnWndProc(chkWndProcHooked.Checked) end; procedure TForm1.FormDestroy(Sender: TObject); begin SetNewBtnWndProc(False); end; procedure TForm1.SetNewBtnWndProc(Enable: Boolean); begin if Enable then begin FOldBtnWndProc := Button1.WindowProc; Button1.WindowProc := NewBtnWndProc; end else if @FOldBtnWndProc <> nil then begin Button1.WindowProc := FOldBtnWndProc; FOldBtnWndProc := nil; end; end; procedure TForm1.NewBtnWndProc(var Message: TMessage); var Item: TListItem; begin //Make new list view item Item := Lst.Items.Add; //Set up new list view item with message description Item.Caption := MsgIDToStr(Message.Msg); Item.SubItems.Add(Format('$%x (%0:d)', [Message.WParam])); Item.SubItems.Add(Format('$%x (%0:d)', [Message.LParam])); Item.SubItems.Add(FormatDateTime('h:nn:ss.zzz', Time)); Item.Selected := True; Item.Focused := True; Item.MakeVisible(False); //Do not call the original window procedure if you want to hide this message FOldBtnWndProc(Message); end; CLX Having seen the VCL solution, we now need to see the CLX solution. To intercept some specified control's Qt events, we need to install a new event filter for the underlying Qt widget (as opposed to the CLX component). The event filter method we overrode earlier is installed by the CLX code, but we need to install a new one of our own for the specified component. Unfortunately, installing an event filter for a widget is not a straightforward job. An Object Pascal method cannot be successfully passed to the Qt widget, so a hook object has to be used as an intermediary. Hook objects are implemented in the Qt interface library. Their job is to act as proxy objects for Object Pascal event filters and slots. Whenever you need to install a new event filter, you pass it to an appropriate method of the hook object. The hook object installs its own C++ event filter, whose sole job is to call your event filter. There is a hierarchy of hook objects and the CLXDisplay API defines a number of handle classes in a manner that mirrors the real hierarchy. A portion of the hierarchy is shown in Listing 11. Listing 11: Part of the Qt hook handle class hierarchy type QObject_hookH = class(TObject) end; QApplication_hookH = class(QObject_hookH) end; QWidget_hookH = class(QObject_hookH) end; QButton_hookH = class(QWidget_hookH) end; QPushButton_hookH = class(QButton_hookH) end; QComboBox_hookH = class(QWidget_hookH) end; QFrame_hookH = class(QWidget_hookH) end; QTableView_hookH = class(QFrame_hookH) end; QMultiLineEdit_hookH = class(QTableView_hookH) end; There are flat methods defined for these hook classes as we will see later, but for now, we need to know about only one flat method, which applies to all hook objects, and it is shown in Listing 12. Qt_hook_hook_events takes a hook handle (standard fare for a hook object flat method) and a reference to some method. Listing 12: The common hook flat method for installing a new event filter type //from QControls.pas TEventFilterMethod = function (Sender: QObjectH; Event: QEventH): Boolean of object cdecl; ... //from Qt.pas QHookH = TMethod; procedure Qt_hook_hook_events(handle: QObject_hookH; hook: QHookH); cdecl; The parameter definition for the method is a little imprecise, as QHookH (or TMethod) is a procedure method with no parameters and using the default register calling convention. The event filter method actually has specific parameter and calling convention requirements as defined in the TEventFilterMethod type (which comes from the QControls unit), so a typecast will be required to pass in an appropriate method. A sample CLX project is supplied (EventFilterHook.dpr) that shows an event filter being installed. The code is quite similar to that of the WindowProcHook.dpr VCL project, apart from the event filter itself and the code to install it. That code can be seen in Listing 13, where NewBtnEventFilter (defined as per the TEventFilterMethod type) is installed using a typecast and the aforementioned flat method. Listing 13: Installing a new event filter for a Qt widget type TForm1 = class(TForm) ... private FBtnHook: QButton_hookH; function NewBtnEventFilter(Sender: QObjectH; Event: QEventH): Boolean; cdecl; public procedure SetNewBtnEventFilter(Enable: Boolean); end; ... procedure TForm1.SetNewBtnEventFilter(Enable: Boolean); var Method: TMethod; begin if Enabled then begin FBtnHook := QButton_hook_create(ButtonEx1.Handle); TEventFilterMethod(Method) := NewBtnEventFilter; Qt_hook_hook_events(FBtnHook, Method); end else FBtnHook.Free end; function TForm1.NewBtnEventFilter(Sender: QObjectH; Event: QEventH): Boolean; var Item: TListItem; begin //Make new list view item Item := Lst.Items.Add; //Set up new list view item with message description Item.Caption := EventToStr(Event); Item.SubItems.Add(FormatDateTime('h:nn:ss.zzz', Time)); Item.Selected := True; Item.Focused := True; Item.MakeVisible(False); //Return True if you want to hide the event Result := False; end; As you can see, this new event filter does nothing much other than add an entry to the list view. If you wish to stop an event getting to its intended recipient (the Qt widget) you should return True, otherwise, return False to let the event carry on its journey. Notice that a private data field is used to hold the hook object handle whilst it exists, and that SetNewBtnEventFilter takes care of creating and destroying it. I should point out that if you are merely making a shallow derivative of an existing CLX component, there is typically no need to create and destroy your own hook object, as the ancestor class will already do this for you. However this program needs to be able to install and uninstall an event filter for some specified widget at will (through the checkbox on the form) and so a separate hook object is useful (destroying the hook object uninstalls the event filter). A widget component's hook object is accessible through its public Hooks property. The only thing you need to check is that a hook object of an appropriate type is being created. You will find the pertinent code in the ancestor class's CreateWidget method. Listing 14 shows the CreateWidget method from TButton, creating a QPushButton widget and a QButton_hook hook object. Listing 14: TButton creating a widget and a hook object procedure TButton.CreateWidget; begin FHandle := QPushButton_create(ParentWidget, nil); Hooks := QButton_hook_create(Handle); end; Again, the results of running this program are rather similar to the last CLX project (Figure 8). Windows Notifications vs Qt Signals We have now seen how to gain access to the general mass of messages/events that are directed to a given control or widget. However, it is common for individual controls to keep track of these messages themselves. Whenever a combination of messages/events arrives that indicate something of interest, they tend to make a special kind of notification for any interested parties. This section will look into how we actually pick up these special notifications in case we face a situation where we need to provide custom responses to things. Again, component writers will need to do this sort of thing a lot, but normal application developers may also find themselves needing to customise component behaviour in this way. For example, if a button control spots a mouse down message, followed by a mouse up message, this indicates the button has been clicked. The button will make this fact known to the application in some way. In the case of a Windows control, the button sends a notification message to its parent control (which may be a form or a panel, for example). A notification message is either a WM_COMMAND or WM_NOTIFY message accompanied by appropriate information. For component programmers, this makes things tricky. The button has been clicked, but it is the parent that is informed. To help componentise things, the VCL spots the notification message being sent to the parent, and sends a customised version of the same message straight back to the button (or whatever control it is). To ensure no ambiguity, WM_COMMAND messages are turned into CN_COMMAND messages (the CN prefix stands for Component Notification). The button component class can pick up this message either with a message handler or in an overridden WndProc method and respond accordingly. If you look back at Figure 7 you can see a CN_COMMAND message that indicates the button was pressed. So, VCL programmers can pick up special interest notifications using the same approach as normal messages. By contrast, CLX programmers must use a different approach because Qt deals with special interest notifications differently. When a Qt widget receives events that indicate something interesting has happened, it emits a signal. For example, a button has a clicked signal. The signal is connected to a slot in C++ Qt applications, where a slot is a compatible method for the signal. Again, due to issues with C++, Object Pascal methods cannot be used directly as slots. This is the other reason we use hook objects, to connect an Object Pascal method indirectly to a Qt widget signal. The hook object has a method for each available signal, which takes the Object Pascal version of the slot. Whenever the signal is emitted, the hook object's slot is executed, which in turn calls the Object Pascal method. To learn how the VCL and CLX libraries enable you to react to these special notifications, we will use a button being clicked as our example. Clearly, you would never need to use these approaches to react to a button being clicked, as both the VCL and CLX button components do this for you. However, it makes a good example as everyone can relate to what we are trying to achieve. The principles you observe here will serve you well with any other widget. VCL In the case of the VCL, the job is easy. It has already been mentioned that a button being clicked results in a special message being delivered to it. Therefore, to pick up this message either requires a dedicated message handler, or some code in WndProc. A sample VCL project called WindowProcTraceAndNotificationResponse.dpr accompanies this paper and shows two things. Firstly it shows how to trace any messages that come along (as we did earlier, by adding descriptions to a list view). It also shows how to pick up a notification message and respond to it. The project uses another custom button component, TButtonEx2, from the ButtonEx2.pas unit, whose WndProc method can be seen in Listing 15. You will need to install this component unit before you can open the project. As you can see, it just checks the message is CN_COMMAND and then checks the high word of the WParam value to see if it was a click notification. If it is, it calls the OnClickNotification event, assuming it has an event handler. The sample project has an event handler for the OnClickNotification event that displays a simple message box to indicate it has been called. Listing 15: Trapping a notification message in the VCL procedure TButtonEx2.WndProc(var Message: TMessage); begin if Assigned(OnMessage) then OnMessage(Self, Message); if (Message.Msg = CN_COMMAND) and (Message.WParamHi = BN_CLICKED) and Assigned(OnClickNotification) then OnClickNotification(Self); //Do not call inherited window proc if you want to hide the message inherited; end; Note that you can still prevent this message getting to the button, so you can prevent other responses to it occurring. However, the VCL TButton component actually generates its OnClick event after receiving a mouse down message followed by a mouse up message. It does not generate it in response to the notification message (for its own reasons). Consequently, by stifling this particular notification message, you could not stop the OnClick event from happening, but you could stop it by stopping some other message (mouse up) from getting to it. CLX In the case of a CLX application, things are a little more involved. We need to use a hook object to hook the clicked signal. A new CLX button descendant, TButtonEx2, is in the QButtonEx2 unit with the relevant code in it. Once you install this unit, you can open the sample CLX project EventFilterTraceAndSignalSlot.dpr. The component has overridden CreateWidget and DestroyWidget methods which would be where the hook object would be created and destroyed (along with the button widget) were it not for the fact that we are inheriting from a class that already does this (as we saw in Listing 14). Because of this, these two methods contain nothing more than comments and a call to the inherited version. Listing 16 shows the main parts of this new class (the event filter has been omitted as we have seen it before). You can see that the HookEvents method is being used to set up the response for the clicked signal, which is a C calling convention method called ClickedSlot. All this method does is call an event handler if one has been set up, and the sample project has such an event handler to display a simple message box. Listing 16: Setting up an Object Pascal slot for a widget signal type TQtEvent = procedure(Sender: TComponent; Widget: QObjectH; Event: QEventH) of object; TButtonEx2 = class(TButton) private FOnClickSignal: TNotifyEvent; FOnQtEvent: TQtEvent; protected procedure ClickedSlot; cdecl; procedure CreateWidget; override; procedure DestroyWidget; override; procedure HookEvents; override; published property OnClickSignal: TNotifyEvent read FOnClickSignal write FOnClickSignal; property OnQtEvent: TQtEvent read FOnQtEvent write FOnQtEvent; end; ... procedure TButtonEx2.ClickedSlot; begin if Assigned(OnClickSignal) then OnClickSignal(Self) end; procedure TButtonEx2.CreateWidget; begin //The inherited CreateWidget creates a pushbutton widget, and a //button hook object, so we do not need to do anything inherited; //If this were a component based on a new widget, we would: // 1) create the widget and assign its handle // to the component's Handle property, then // 2) create a hook object and assign it to the Hooks property. //Hooks := QPushButton_hook_create(Handle); //As it is, we already get a suitable widget and hook object //by calling the inherited version of CreateWidget end; procedure TButtonEx2.DestroyWidget; begin inherited; //Here we would destroy the widget and hook object, //if we were responsible for creating them end; procedure TButtonEx2.HookEvents; var Method: TMethod; begin inherited; QButton_clicked_Event(Method) := ClickedSlot; QButton_hook_hook_clicked(QButton_hookH(Hooks), Method); end; It is worth pointing out that you can install as many Object Pascal "slot" methods as you like for any given signal, and all of them will be called when the signal is emitted. Whilst you can prevent Qt events getting to the widget by returning True from the event filter, you cannot stop signals coming from the widget. When the widget detects that it has been clicked, it will cause all connected slots to execute, one after the other. The TButton component already has a hook for the clicked signal, and calls its OnClick event in response. If you set up both an OnClick and an OnClickSignal event handler, both would execute when the button is clicked, emphasising the above statement. Summary In a 75 minute conference talk, we are unable to look thoroughly at each individual difference between the VCL and CLX libraries, but we focused on some of the key areas, where differences are important. There follows a list of references to other articles that discuss some of the issues raised here in more depth. Further Reading  HYPERLINK "http://www.delphizine.com/features/2000/08/di200008rk_f/di200008rk_f.asp" Cross-platform Controls: From Windows to Linux, and Back by Robert Kozak (Borland R&D), August 2000. This is a good introduction to CLX for component writers, explaining the differences in the class hierarchy and the key virtual methods and presenting the first cross-platform CLX component. Both this article and the following one require you to become a member of Delphizine before allowing you to read them.  HYPERLINK "http://www.delphizine.com/features/2001/01/di200101rk_f/di200101rk_f.asp" The Life and Death of TButton: An Under-the-Hood Comparison of the VCL and CLX by Robert Kozak (Borland R&D), January 2001. This article looks at the TButton class to see how the VCL and CLX implementations differ. This helps give a better understanding of how CLX components operate. How CLX Uses Qt by Brian Long,  HYPERLINK "http://www.TheDelphiMagazine.com" The Delphi Magazine, Issue 70, June 2001. This article looks under the hood of CLX and finds out how the Qt C++ class library is used from Object Pascal. It introduces all the key component areas where Qt entities are manipulated and explains the mechanics of how the CLXDisplay API (the Qt.pas unit) allows an Object Pascal program to talk to C++ classes.  HYPERLINK "http://community.borland.com/article/0,1410,27231,00.html" Programming Kylix with the CLXDisplay API by Bruno Sonnino, April 2001. This article shows how to talk to Qt from CLX applications using the CLXDisplay API (the Qt.pas unit).  HYPERLINK "http://community.borland.com/article/0,1410,22495,00.html" Internals of dbExpress by Ramesh Theivendran (Borland R&D), July 2000. This was the initial draft specification of the dbExpress cross-platform data access layer. About Brian Long  HYPERLINK "mailto:%62%72%69%61%6E%40%62%6C%6F%6E%67%2E%63%6F%6D" Brian Long used to work at  HYPERLINK "http://www.borland.com/" Borland UK, performing a number of duties including Technical Support on all the programming tools. Since leaving in 1995, Brian has been providing training and consultancy services to the Delphi and C++Builder communities, and the newly forming Kylix community. If you need training in these products, or need solutions to problems you have with them, please  HYPERLINK "mailto:%62%72%69%61%6E%40%62%6C%6F%6E%67%2E%63%6F%6D" get in touch, or visit  HYPERLINK "http://www.blong.com" Brian's Web site. Besides authoring a  HYPERLINK "http://www.amazon.com/exec/obidos/ASIN/0201593831/qid=905701291/sr=1-1/002-9464178-4139807" Borland Pascal problem-solving book published in 1994, Brian is a regular columnist in  HYPERLINK "http://www.thedelphimagazine.com/" The Delphi Magazine and has had numerous articles published in Developer's Review,  HYPERLINK "http://www.computingnet.co.uk/" Computing, Delphi Developer's Journal and EXE Magazine. He was nominated for the  HYPERLINK "http://www.borland.com/delphi/vote" Spirit of Delphi 2000 award. In his spare time (and waiting for his C++ programs to compile) Brian has learnt the art of  HYPERLINK "http://www.juggling.org/" juggling and making inflatable  HYPERLINK "http://www.paperfolding.com/" origami paper frogs. $%&;<=t23ij&'lmopEFde  *+LM齰0JCJOJQJaJjCJOJQJUaJCJOJQJaJB* OJQJo(ph 0JOJQJ jB* OJQJUphB* OJQJphjB* OJQJUphA=jt2oXEo.\ )j^ & F & Fdd[$\$ & Fdd[$\$[$\$+  5 6 w x } ~  ! b c h i ~  . / 4 5 J K       _ ` r s 3 4 @ A ] ^ /0qrwxCJOJQJaJ0JCJOJQJaJjCJOJQJUaJXRSXYno78=>ST $%gh{|<=TUpq&'HI&'hino0JCJOJQJaJCJOJQJaJjCJOJQJUaJT  ^_dez{  st)HI b p W![!]!m!""q%r%%%%%%%%%&&L&M&b&c&'jCJOJQJUaJ6CJOJQJ]aJCJOJQJ^JaJ0JCJOJQJaJjCJOJQJUaJCJOJQJaJOJQJCJOJQJaJo(Aj%IQ [ b p ]!m!S"$R%%% & F dd[$\$[$\$ & Fdd[$\$%%'''''''v(w((&)8)))W**+g++Q,,9- & Fdd[$\$ & Fdd[$\$ $[$\$a$$@&a$[$\$''''''''''''''3(4(5(t(u(w((((((((())#)$)&)8)9)))))))))))))L*M*T*U*W*X**Ǻ鸳܌OJQJ0J6CJOJQJ]aJ5CJ0KH$OJQJ\aJ00JjU jUo(jCJOJQJUaJCJOJQJaJo(0JCJOJQJaJjCJOJQJUaJCJOJQJaJjiCJOJQJUaJ5******++ + +++]+^+d+e+g+h+++++++1,2,N,O,Q,R,,,,,,, - -6-7-9-:---------....r.s.......'/(/)/*/////////////X0Y0000000000CJOJQJaJ0JCJOJQJaJjCJOJQJUaJX9--..)///00R11?223i333355677D7[$\$ & Fdd[$\$ & Fdd[$\$ & Fdd[$\$ & Fdd[$\$00K1L1O1P1R1S11111118292<2=2?2@2222222222233V3W3f3g3i3j33333333344 6!6u6v66666667777D7U>]>?@!@鴰5\5CJOJQJ\aJ6CJOJQJ]aJOJQJjCJOJQJUaJ0JCJOJQJaJCJOJQJaJjCJOJQJUaJBD789:<>U>]>?@"@.@/@6@u@yu$$Ifi0z 0634iab$If[$\$!@"@-@.@/@5@6@t@u@v@}@~@@@@@@@@@@@AAA$A%AOAPAQAVAWAnAoApAxAyAAAAAAAAAAAAAAAA8B9B:BABBBkBlBmBtBuBBBBBBBBBBBCCC!C"CNCOCPCUCVCCCCCCCCCCCDDDCJaJ5\OJPJQJ^J^u@v@~@@@@@@@AA%APAQAWAoA|$Ifu$$Ifi0z 0634iaboApAyAAAAAAAAAA9B:BBBlBp@$Ifu$$Ifi0z 0634iablBmBuBBBBBBBCC"COCPCVCC0$Ifu$$Ifi0z 0634iabCCCCCCDD8DDpEEEEEH{{{{yyy[$\$$Ifu$$Ifi0z 0634iabD7D8D9DDDDDpEEEF8FAF>GDG|GGGGJJJJiKKK*M4MdXXYY'Z.Z\\``a a!aYaZacHdSdedpddddddeefgg{g|ggg|hhhhhު0JCJOJQJaJ6CJOJQJ]aJOJQJCJOJQJ^JaJjCJOJQJUaJjCJOJQJUaJCJOJQJaJ5CJOJQJ\aJCEEEEEFGHjJiKKKKKLLBLILNLVLZLxLLLLLLLM[$\$MM!M*M4MM*OPRSaTUXdXXYYZ\^_!aZa_a{aaaa b[$\$ bHbpbbbb-cRc|ccdexee&fffiKiPi^ibifi{iiiiii[$\$hhhhiJiKijkk1l7lXl`lrrrrrrrrrrt't1u9uuuuuuuuuwwwx xxOzWzzzzzzzzz{{K||||}}} } }}#$%δjmACJOJQJUaJj"CJOJQJUaJjCJOJQJUaJOJQJ5CJOJQJ\aJCJOJQJaJCJOJQJ^JaJGii+j@jkjpjqjjjjjkXl`l!mnpurs,uvx7zy{K|| }}#[$\$#$^[)W%ъCu!Ѝ[ & Fdd[$\$ & Fdd[$\$[$\$3: „%&r}[\TUdeSTij׉  .0?ANSX|Ǐ Ȓ͒0JCJOJQJaJjCJOJQJUaJCJOJQJ^JaJ6CJOJQJ]aJOJQJCJOJQJaJM,ԓtڔNז)*QǙ ֛PT & Fdd[$\$ & Fdd[$\$[$\$ & Fdd[$\$͒֒O^`|~ѓۖ )DEDENOQR֛ҝݝCQϞ}y0JCJOJQJaJjCJOJQJUaJOJQJCJOJQJaJCJOJQJ^JaJRg5 uV]$0&>X1v[$\$ & Fdd[$\$,<@K+6V],5FU[>Gͧڧ#$/01"#$%&=>?fnŬˬά֬δΧjCJOJQJUaJjKCJOJQJUaJjނCJOJQJUaJjCJOJQJUaJ5CJOJQJ\aJOJQJCJOJQJaJCJOJQJ^JaJB1uv0<EQ_gݰ&1αڱ Yb,eqouʹڴ @JS]ε׵$@N&7CVb %øOJQJ5CJOJQJ\aJCJOJQJaJCJOJQJ^JaJUϭ,<KUcsȮ֮ *=TeexկݰY_&sv$If[$\$ֻ׻[\zGMipMTV]3N*0CH6QSprHTXb7m/63<t}GH5CJOJQJ\aJCJOJQJ^JaJCJOJQJaJOJQJCJaJ5\OJPJQJ^JNs׻[\zuoiiuoiiug$If$If$$IfKF X|*06    34Kab  zE..3Nt7imH !>Hgs[$\$HI{+q ;RY]hW[4> )*MQ$%V\ah4FjCJOJQJUaJCJOJQJ^JaJOJQJ5CJOJQJ\aJjмCJOJQJUaJCJOJQJaJjCJOJQJUaJF >Db>=>[e)04[$\$4&+q;W[c*/GOYy[$\$+1^cd 7`fm)-@@Fb{W-HMQ7e,[$\$,`%*AK#,ahl[$\$Kb%)=B#(#.<HVw06T[AE< C     ~      f y    X  }&6CJOJQJ]aJOJQJ5CJOJQJ\aJCJOJQJ^JaJCJOJQJaJRGrx 9pJ]bbjVwi1)yAEE w P   / 5 [$\$5 S q   FSX}D-2Cj[$\$ GR,-:.2im '>Eov~/?@4!5!!!!!#"*""""""" ##a$b$$$$$[%\%ϿԿԿ0JCJOJQJaJjCJOJQJUaJ0J6CJOJQJ]aJj6CJOJQJU]aJOJQJ6CJOJQJ]aJ5CJOJQJ\aJCJOJQJ^JaJCJOJQJaJ<07;]cGT56de LLy~5:/?4!"a$[%H&Z&'( + & Fdd[$\$[$\$\%%%%%H&Z&[&&&&&&&&&&&K(L(((((((((((((\)]))))))))):*;*g*h*q*r*****++f+g+++++++++++++o(0JCJOJQJaJOJQJ0J6CJOJQJ]aJjCJOJQJUaJCJOJQJaJC +++[$\$01h2P. A!7"7#7$7%S DyK http://www.blong.com/yK ,http://www.blong.com/Dd*<P  3 3"((Dd*<P  3 3"((Dd*<P  3 3"((uDyK @http://www.blong.com/Conferences/DCon2001/VCLvsCLX/VCLvsCLX.htmyK http://www.blong.com/Conferences/DCon2001/VCLvsCLX/VCLvsCLX.htmDd*<P  3 3"((Dd   S A~http://www.blong.com/Conferences/DCon2001/VCLvsCLX/BaseCLX.gifbY@h=;[knY@h=;[kPNG  IHDRE?|PLTEwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwxmbKGDH cmPPJCmp0712Hs>IDATx^]vͬ{֤g^$6I3mcl%FÏn?."pQ*V8?||8z0۟?&iȲ'0"kaV<$-,6Xqq鱶$<u4(nn@vPJlqY/)Z/S~ݢw6!`s+-/^Hdnu5:>ĆbbȔX{D`fN?#6H2 uD-ALlEq{AhdEK.+Ӱ3k,MfWxNl¢(f`e,K 3OGj![g'=]q[:ȾMK M= $gl _1S@blJB-zq8: f\c4[w[q#'Xbܫ>CKt|'6)=b3Wj|߭v7V7iin@>> jkCQ#^[ۗ ׃4KblLc9'r7p܊,.·(ɇCnѷOۻo)tYLŭ29~TQbTߢovo n_!q .8+lPoX.uÿ/o ѝC EOc{6E95~w^`bEݍY2ԉj7^!7cھ˸5P,7p e€D9OU\ܑ_/QM9`/zd#z[CKJ-̷N+(h+G[B(VF-ⱘ>66y(-E1fͩ0/#>[?(Ǣ9U}([!x jΎ\P{-W=֗cEzWz̼W?_AH3e .E107ZA"R:ZHpEWOP!u|3VŅahѦ#j35ouCB,ؾm~\.u cwh^Xa5_h>GRMB,:F%$>ӠY0((7Q<ܘ@1w\G3 8DlQ҅]x"X[J(x`wmuF7~> .шZ,:=ڢ1a۳0 tC̾p@zbGR~7 Enm(x8WVLQ@Q5 E7y .3^8.v+ktIHA "$Et/섄1%.^93iQdog;3XHx`B f̾z Pi9b-/xwƲ#.GMY%洓an gQ"G+:N9Wߖ!u Z4d~2yN<UŗX pdelX5U1sL9 #o7=~|q.h `BeEE2[@SU!q(F73%H>qޣs(+ZUq1nRAblU.`Q<7li۹qp"I(fP^r1n<[qs1.67b% }m`8/9q14/7}lG.j |\dsQDPs͆ޜgWE$]bdb`sqb[hрC2JCţ h/Q-p4zp VPΩDs.V̮rSeVQŽ1J0ciSEp(+'g\t}"7FTq/*SAߥcV~8C_;#{(H]P$*a[EX:8c{ڕK!-0r3@q9&H_킔 Fnߥ~Y5SEO,5a?D@EgpEl}e ?NSŞ;y7D@dXRHmA)1PRr! \EF.B*Mm9"p1Ma [T//c_@G''.b1/S{1% c|Bh-9v*닮/H<[E慗:^̠RB^t}quhTE:+2 GG;Gg}ЖrhM}[Oi 0r"S_DYĿ=\DZ)^\,.lrѬщi)=VMz*\}Q$ўR#FY-_H\\E/^aK(d)<'{}_]ls8&Ode\ݼn"G1-Ǹ?ɨ@i80M7zpV4 1*O6\D@Єb"P.i}Qɥ˫Uq3a". Ŵ{\|cE]_\t}cH]zM2EG󣍩\b~x~tw]w(;z7)?׀I}1i` k#b蒋iL.sUNtn,VGcGfnY=I]_t})!S/Ѿ"ǢiM'/&\Py 7,,P__\EL}q[E7:ۋ]jYQ0ypO(0\}1o?T&.W\/(11?/(֛Iۣ$.1SMqQ/"v9-~/\ųq).E,/FN /ŵQn(WU\/_4E]qRP3/ɢC1f.k$*, fTq/@4Nߙek%![,P@]_īxbBSEpXbe^Rˉ-e rw:ce۰5*3E@ɬ,į%}ԅta\8Q_LEpY뎴[E/*mk|Tq񂾈YCDмKmn]΀:ȹ/Ph=Rif@l(c\.r#764GW6k/q=y{3?wEe>)ER_Lw*tJs.#G00*bw&aOLK+(MKD{U,,5ޠɹ .BG{ FEE X 8ʍ8eΠ}qU)(a^Łm񬝦b /¢0}}qIIՎkmTbT.T]f]\_my{Q| (bϏX4>?:!s؟oQtZ.aLKI}Q$b[oKڹE~Q/)xKQwqʼ["s]4N4e }f/aqB^^5\t}t}QlYr.o@n{/r,GxHEp/-p(z-=q/bZbK#(6(R.=a*LSP*_L.D5[)c)ɍѤp= sR`ŚhbwŎE+KEB9Xl֦AU\ŘX!-i/y .(&[,P@]_XbQp9\<ݥQwL=j{~x[* 6M)8*]7XEh} 6\l؀4~A=wM)9j["E0r #yڴ&^^t"A=`P-&pI_lm)sׄb+P"dM^~/sx<"Tzt.I}1KabVxVv Ex%ѥ1?zU\l̏!WX7\W є((r(1Eb .z.rX/ Λxku O_+zۋ+vK^k"×؅u>sb3/nx;nת,vs?@$&LBQƭ5TqqrE@dM85~P[t+>EtA {[ ..dMp~t%9=~Rj(xlU@RP%KAŪy4mkDǕ;%IENDB`Ddx  S Ahttp://www.blong.com/Conferences/DCon2001/VCLvsCLX/dbExpress.gifbAQ0&l\&H"nzAQ0&l\&HPNG  IHDR$~PLTEwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwd<bKGDH cmPPJCmp0712HsIDATx^]r㪲ujO]nMo/!2GBbnkn)_7@Soj#{ٯ{I Q٧y"Oz$D8[pq ϟYs>(_zOd:lApea"\tmȺս9κ/ٝ~rȢE}T,0&J#Vm٧qXSۃ] Y`lSAgg&3tDXs#.@suG)Ⱦ-ٯ?__FT8(tԮMQO7v!X! VLmhٞxC oFA=_?k |}4j"^]EK7'"d׼=KKb1w-š QC[+JF}mnd*F}El%J3Obk#mܯ h}1JRo۴L5c; :GT_;p,2KSiB\{KyC{˱g ndMs!_߅11xY{ ٟE H@J_"DžtQ-Py`A|8*3 b=4{Q#z"T dv`v=t Ì"I/.@әpvhtQ@d"weFV8='iB}֑)iV!M&Z,Lp'"olzu>zX"8\Y)fC6pp*&ڸY4ԑ;˃LSIByΒ!&r3ۍA/@('*͔0>4]VP'GФ]127 3>s6,<+N3>Jtv|GwnUj├lɵloSFCYGEY{! &c \P|Aq%kgȱq BIュZxVf4*gE,ƨ'BVlMF'- \=5Aijgw~КƵxלQ Y.֮g-~6Hc4gCd@MR;+nw8_wOl`ltp(k h,UQt%cs»OZ7G=d3g&3Lݭ%g\SQ4F:.p6Ax:o6ΒZ+kPÐ Y6d:նB'o *d>ڡ7 ^#3|mlgq#~ļt;i:9ZڥC F3 Z .\hOCKJf'cƠl*Hvo ^dg.Rnq E zZo8'Zg!/I eq7 I8yg:D)gG۠܃WD6%;mo Fx)9Zf.K$a|>fm3,֜pNYޱY #m,KB ;s1{˄8X6=k`<::gL<A*mv6W!ӞQ<9SWuנz5%8kgKR'>3fϖюo.ndL_ g "¨,1{;]SџV S&"YܼX0јyjM_qxf`5F;˗G$ٍ YSqYoi㍬ ١};ګųTq*b6̧>Lm~Pfj ژ (c<߿sgӚ RM'gBH>}|c1f1 ]"צ:IMi[%0Ixp8Ha^}#Kdd8 k' Tb]ȚnY\\ KGub} 2B]]ɞٗqG TA=JE#fU%EJ xZfc@EЌG.ζ߼.,Y\wLGsoUOsU ̱YMkk6A>T'bųlZSAǢH@v9 E' 0Z om1;;6? [[u~6,:qh= p^G*苜%b*B6" jbƒ{w9׃9CY8iwx\a (`,DR&@MJ:}7Φn5bb-7Ik/T{/ 뙺5*@FXȆGH/UQ,]\$ F:Nf]7hC8ىna0Dz7ތF@鳌!\ڵ-ijudi "wFqAq-$i>`5dE c֠llIgwVPSҗD9Q|&9}_i~vT1_75Vv #5lO4rvY۔}gU_wUȦ5< ;9Odl 9kga/NƝS1)Ɲ5O<{^SAˋE7ynXg\4FqcIټ%P9[svx-dxpڝ9 F;pΪ\N:MY)ELn/4ip0[xPzq*ϊAy.2AfoggovT-sN# {{9"z)dkL%F|^]lcb ٿ~Ï㿍l/x6z<Wk$wm쮩yY8;nd p ,~9zFu#D XpAFvPҷodWDZ;8;Nš߿gG*kןggv%)z^S|k%gNkIcYyYL-Ni,;5,$sd`3{'j_z4q`T@S>_.#~2) n3P syWgl ţezD~dknP |&?gqqǏQ0RbhU>oz,}9~H(TՖ؜-m̕w;-h&S\Yڜgvl} Yquq6Ƴ7stjc<> p980ngQOmgkv?a@/UgK"Uִq%oZG/"Y*'pܗ[&7gk%rM G'E}Lwya5Ƴy; T8zOvp6[srg߮mN.]Ȃr*: *Z?ޙC|cP7pџhc:d5L& )W\AcуfMlGKD9DQ*ȮqldGKt6 1z]*HG17asv4WVo# DZ-UȮqldGKt6 1z' SW |:IENDB`qADd)  S Axhttp://www.blong.com/Conferences/DCon2001/VCLvsCLX/Indy.pngba@5?9y~WH[=@An5@5?9y~WH[PNG  IHDRMՎ pHYsod IDATxy|LWǿSmO鯨>Of+jcߋ" dRRIZ"QUB$dLHH(Fm$DԾØ{;{|{~,33?! 2 ,X`EPH$/   AA4OHAAh@?  @A ~3q  g+Pq"ofoYSI C @$dy S|XMO  oB ~B}Vū&'"ܔ 4K`}dž:V6k^ ?@A' ' 媲/:NSYo  OЛWU2K  ;O@A^q'3~B*+'=MX#  H8 YAALr AA46  'AAx~AW1g1 臊DB4r hA00cCSYQi3*1JŘ4T|AEUS %'dȭ1uFͨĘ6LLZ<oF` #0'W846cB0 |ԩ/f~$D6nX́?AGffTbLHBg4GIl(MU'0hZZBa=<q L]$J+ ( 袣 фM-Bm5՜@Ys' ZGR E"Dq W!?APS?E_~B顮VЯ\S ~߼iqԵ`|5O'V#UI T:ZYUjk Y$OLf¨tb7?AAo~BGЅ6C 3ش0ނ+ɬ^_] b\Pi\UJ kdծ/!ɪ+u=%Fm6!ZڸSh:ZTڃa S*<-bMrOp \I PаkTbmjd>1wpMJ I>a~fudӆ&/ͬT/9IxMh d ZѦiwF&y S6լyPkj3P~M@DUR /R`w׬k% UYIZ1"HUF &Z?AH8!{wWr$RͧmqBq\#,U9! ͨ RA@?(G"r=\A˔ٟФkXljL#'&'\ZYI`?A0k|hOgoj mՉ'jFXa+g.P4r]LT/'K j:ɝu_] jE"Ĵ)#(E4w,U[pP;y)!LoqD_14M[>wT͕~fq &1V?C Es?kN4Qd\HYgח0OTK\1 V1w$hຖ5f. Fm|rBYe KAjzGZzm|,ieJa,pR311Q7աa XCtG*>fEfak[(*QyQTR`uTv^Omݟ7oGW;)xаn;o:~avZv-kц9+G++@WoVӦ\|>T\|ONT?6MM$#QT$.$޹ѶnJlV bQg O nLؾAtʩ΍dIԩ+]c`X?5{#S2BsO(cj=GviՇ9Zcyug~9wɚΝ<[sܥ5g:mo۵cv+[ָ$[QzW=ٵ[Ϝܹܖfb՘okh)LOhLނ刏u!YY YEȋbyoݥ9lcɱM/yW/]UȉSi3싑ڵ/;Q#y#sɑf.\oƮO CY=2&FNjUeHK$ 6M(YPsL3Ϻx o4t y͇m_zYoCM&^' ߀%ª+X,@pbϕٹ䘉R^^'/FTgm^Y'l,b|C_ vnKMqhlmh>FzY=sI}{O>e4Wy:ea”DqOd*K&O$h"66䧦}IS)vGhf޾m"j;wA3; Y#uѧf;m8ޱy/]Ii۴mߡV&\VKk8̥L,.Y;|yK[dHʹKClgOMJu\2y/l?<2CSab^-Z,O_Lӗ>fuw2)Q\17e.5^">߆Hte܁ʜ\BLžDyy9(1x}/my{k'!! g{-^t 1gg.++,npɊOWTc唁#13yN6-mMc3~hkQfcn!=~Ultnλ}☩ a<@]Ɂ,|DLȼkLjZ$?!_ zemRuaP1B|/!=~ѲmћDA/Ŀ~gzuv.;v谈9ulvmڮ5Ƭ0ph- 2lSfXD˿_~qi6mNuskg4~8\~+7X 3K W23KN<>[R:2ig;ltd=^~Fe)k&qW)IZ&&;Dmt ʑ'Z`oCd?+ p7 1y %K2;wh/@;Oh;D &uMUZO,B@0Q ų!. |3L3Νp9j,D$8&:w>~9sNa}"NDr*3?ȸN׺w#O+>)п疂\G?~j{Qq~$I_yw=wNcĎΖbGfNWM60;ENхͰ6Sׂ}ptk>tRoiIbH$ zaƮ=vq<^g:UsʝGWs?nX-1|5qN6vbzf|s1=FX,[Ϊzuuc; sav.yka0z=sa}[sÖdr%r+QӧG9)f㦝[SxTbPl([i?x@\BQRJ[ဪ.TM}kӓi [;=}J9EI)EI)^}@HxL3EZzY?;^9y51AZ?a0ʹWKSzQ-)ŧFc27n8nv4ѹ8*MЯGo5jR˳)BVA.T>}ﮦU^.8CmOzy\=l#zhi!ZZh%mDNsAbJ#\9dޣh?יYiWr>K6bm)5rh]j;SgopݡS&k}U#\!NE. ) |Ki|bIH͸ 0Y h2O8ȋ"dǨ3(Ԋu_JoټIdoҹy\/D=-zG;dKm,hqt:3CQRjӺuR[}D-d,\ ǵ1|Us+l$|4nqJ}찗n/{Jr!ߋb7m&v(jco @PP[Lmp+Lp*cHF`/65pvp H'~|```=[H6<11,'gSVV^Hgr I)SA.i<>$?bTTSSSPPPgggUUUaaaXXǏ􌌌gooo"K}|C\xBd/֢2bh+ۘv%X _iY柌{sM UAA̬,l-OZ61#8"8]haqX=-,NUpAR?/_òjX$o{8}1G_~6B\lk6=;BL]bXZ93G o"#"#;i}Ck]#zΉOpHȨ>=NY#⡦qG59e#B3ꐖ۵[co*9ehhhz.&: ғ,Lޏ(~i(O0(TJ}bVt'R,f3<%*IA阎RS@nӳy.rNDglMM= ݐsgD4eqiG\M5X3s;<{%V'@I(2Q6,I913N.%I}jfuRXo=o~50x]{P݆ȸKSm~a+ݏ&7w?pXލ w_竑7c5\}_LލtQ-)aET(8˚,-a*nY.ERUx_2r͙UYݒs͒JKQ]s:OLH!?Kptbg- p¨^6;v*D8,'8oN ͊m+/"@"#Y S)|nQi'fLJJZF|LJ+.ȋã?<74_]jboK&I"BGGDž <==={VZZnjjH"ZZZڜRjt |rE-kk- 'xY6O,ֆ,~5c###}}GGxAx<Cx%]Ӧb/w/Cҧ,wLxG' y?%/AO9Rӕ[7YLh1# Exv**PS\3rtk]u T)|…'X N/wʓC^7'myqm]Nv5}Ң?8 -+쿾XUMtRҦ:q96cȝ}COG :ɹZn m w%t}?A%h}1z/jU5>9jylˀu=8mo:Z{.J^ʏ=s&d+]i\<;3|P.I@AP8!B 9/4&%@(L/(1 ê8`E't:‡,+ζ5 A'''l6HKK*(kBү I[<== ͞LNNFDMc D^+)[e_Rrڵk>>>555qqq!!!4۷%%%...~~~>4-yy/9||D.!EFߌ{[}'R^q9$,t9$RjaX8->z<->,znwaRZ{P뱮c}bRl:ZZYX^zh]êJ mF*魒ŃP$kcxho3~퀓7 LP jh5F$ՉuuA]N khPl~Tbl$=O^?ߡwߢ\{x5^kmYT<ۮzQvSRK?O21;OHU}Ԟț)]y]y=XvG>YOt1o U=}?ݞ=1Z7?=~bJң7+k:\KpZb>[H_gArʢQM ?I˗o߼E|ş}p[͆+4l9kB>1fVi)%=?1g`۾osKkdd{9L\籗={yіnw=zgG^?zLMߛaLv)OV8ŧ0 S`xbRW" A $քӲ=Sm|҇3mֺiVhPN(^7Œuw$ YX?8` %>"(_LK*&f<;)e<1,pOHv"\(`LVcXF OLy&{)xU{crʑio8HnKRRRAAD_Ĉ+a 5jHd2>|qqUUUgggOOO??KKK33cǎYZZ؊$Xv Q` u7zms d#==mm5 mQ@!44ttT **&FWKLK%E`?ryyh|~V=iK Og|w֗hsu55HJnoybiJ5!WϴG~_cAp˜k?E%ٜS{A li  2)rWWȳ_wf}?捫V}GF*# >l>/!{-":Jٰ֮v眜EDBm޳vNN*_:IR>x0ǑDN 06Ks&L>z#Gh ﬙OpdR&c/~ڱ娙q''ܞ?Gzp+[KU%x<>S0ɟoDЇ0g>OV1ͶK1wdSLOUÔyDLwf-rKLr8E!1HncZZSFFkBӟqBcH.'Ƒ8]em-(?`PxJX?XNR_@ 97>XW[}s >GN0>9;,N(h'GxbzQi~xx$0KxYػ&m"J&->>>^f4<%;@04|20rV[MKt&^1-G}fS/;p&ѱX{kNT/yC%\|m5UYʘ YCn\tBH ?qDPPŪ777';lalv^NiߗpXMArrsQ|%y؟52ZꟵ77u10ko~f1߸Z+fT旖r^xaZRzgn`/^ 9Zz hs62_z>#6+vO H@ \T)`gQ~^`;{[]]111_k+s Em3'8\kiN XjzZ{P[Pۍo4T}ɒ5*aBرL(?oFrC`|Zb蠓l)jiyL$ #2H1Lo1}"f6<֘N9-C2o#6j#u4(p$-@@@@.@ AT!w f&tO>>okY+sBL.%zY(+)^xH$(++s5nJ7X P7c/1m8VV^QyzE*vIMmqmyiUEIuuaeqQ~-B9 !5v]T`Vj8kXOyiX|f])esq@>fs![ε OQ{6}3igCh[ڑ:x1Y6X mꉲI:pDf6+ -+ -#U3έ۶ofv)-.W6<|dJ2;e.{hLNHk{᰻ooM= OevJj2/&Lwjs5w?}o>Lc4~W.xLzSy`ʜTDbp"EAS< i;:dfR|?D>KW? yP#]Hcp+~a1߬UD]*` 9Hfr?0n҄  a9p6乿['=B^c-p ˩nF&: v<l8H8 _/jgR 5'am(,fK<1D[iUs|~X u2?Ca]{ w:ocǯ|?(4ts=l_vfya¤:ns}8>&x<-^Jκ{|Jߘ<:?'E2ǁ2YDQfڢ`i5;>Cs 3aNES;L$ɬF]0=KN>W U ?~X6՛'H stֶ[&2R8޻O||?WAL%wGwؚ @8n)*ӹӑdg'[ԯ>ym b0"R0b])O̦f牙n`0MDO'I;?  ӂIg9L\'ߛ3zKUA!Χi~M8rynR4%b_v9MGO.fzixONa}U?T4~_?F9)OƶÏ:֭uf[ƩjW2˯~?ܢSh:5I4Ʃ=_߿pFM}r@u.4@?? N,[ t撱~g'ğ'vVk}+#O(w>ӈSph z4w0%Bh"xvzDLRgƸLJo3e}~iT6+ @61?_`^r厂 8-.;-NI3Kb}wX:/qdUଈK+:0d¥Ijo29P^D/|f}$w@Sp.ѝGfD=o:̏dNӢra˧'^A[80h<QwkK E p͍s+ZV'ދs$sjq'6؝\P'sֳmqWR;kZ+4hIHî(n[_h`.1HLf>+ X钩x883 8`J]Qnw}~YdzE8_9n]*j/($3gIMUp]V@p]$8'fܘ&界u8}{( Q6P(7 r&3 :{ hIwI,\t]N9M2vB,}m8U6|XJ&G;= Oř'js؝\(VIrѦ]Wׁ !J<(U(fs#"8g  ǔrƝ/YʛPzN'Ǝ@\q;= %8 , LG%)ʼn llP4{6(]t1|N?Лu)}Y@8MC4|dV#Z)resD p{8`n3EBcR[46m6c8 ʖk8)Iz DcwDq* i}G8n;ak_؛Ҏ;ad%T BvL@3uQ >󶝆p,lNW֛:i܉^:J\p%Ҭψ(E!(Qz 8,2VRE|2/g(Qz6v͑UEP듋pJ6!zg2N/L.e$#t;ᄺ,bƌS;[|x+JJ3a>[vָK:lj!je= Fg tn\ݕǝhK%M2sx: ld[ fb>ja4d)622N,pj ψ~utEn_O6 aSp NqWN֘Vsǝ6Dl%HG:6sQ5N &=dxaj )t4+s8l'm2dIpڔg[P'F>0,WsRmuK)yv|[4vݣ,\U'>ƙ:-]6XU3zCkhdi{ }f4Pw6\u.|#WMo '.A*8y8b+^}'+hYsIύ;+^'$riͿlw w:qLoDiNfjdIS76fo:Dzv lG8 ;Gpz0mz:}2Z*sqjYUTFKj?O B"\p\K8 V .;C=+ geyCpRNҋW{~ Y#Y{¤]=ֶ>]09)Ԯ﬋ng97>ŏb^[A͵[?)R[$9ξi\Mwu6޸ʳ11ԉD uz! =RD(lqOQnYk>FPgݲVgᄈn3osu6).'=;'_5Nt ՜N[`,N(81D[ڥ >@l}E{]:m^w8)LZ'\N|8V+D ,Z)5*In~kG߉K,q2WZ[X3\W+N_j8\.t}d4&8S(%Sqz`2c ؓ1pXNѣLogR G:(x֏k38ͫ/4$vVb@p4q6d3pR7,1/3RgM,98NwbWdzgrWtة5,tL98k[83cD]Z]6Y<9@ں\&yɍD.K[Wm]1 U3vX}B:ꄃ.CpEUp_7EAcWHwxAǞSwg.8IoH+u NR:')DieNIJ2Q$%@ZSp L)8I V&H+u NRmQg Kh_ Ự{ 4ŃxRfe[qƮbӋ͋?8ILSY58auFqr]L,0N'L_i-ܖ8M"M|2N.4E+| Zs[h xy|Z\<g{\=~eZm;`* N R7eƜ:+){)`źh5m]yl[([F`\zӛI)O1vJAh]L )%.ԉ,+us1)8wnPu3t$5te3hC VL3PBpn.ʅ %Y<++;w!+=;8!Xv>ٟUg81j>s؝1uc[^_'lD8A{[Ǚcj3:KyJV>A*ղ'”[%U vJS]*8Nwi ^iHӝd{yJq){PÅ Fm\yΆ[#p6ܲSIG]|'K=bpvA)Y$|$%N`I8q=rfN 1rKn2XYLidV=oG)A lj =ٷqN%^Ndr_yo.EDǛՌq4YCsN:i2C8m[&Rpg;Ff 8]Ni-DipXa%K Q'&ùm~agSE@ }2autsqOq_rλ *YWLpq,%83Ay2K LPy;JCc< TZYOt%p:8BD* sz1:ljt:r k&jRp}jn ㍜m\m)(Q8u?q4y;8$dNT"8=4M|>f8d]nmwf]Kx4Ip s(֝|dlgjkn`=MUz=+S;-H櫜@/qԔ:݉Vo\J+oƟ({ylt}'1z>u~;h 8K#u>fh Ns/ *ߪ\uF0UԹ'P5Pl su*#L:hJ:M`VS8þ3-h}w)#?{wnJܧ‡|kڎUg~NuB23Nܯ bQ:lTd'H)t\ *")c'.kqB"t)Їp]:݌҅sjL/Jm_>D+NlO;e} \VѾM&pw8;#8KG8?F'.s8ILȘYu$ۧqYp:xXyz:qz>u:zb*|<ǯ߽\b'yz<>~޿ƺ^\qrj牙?~8lW;9It{NO߽upJeKV p~GS“,Ro +iwL;eJ V!<<}{J=r|ï8rN3?Q$D9P$bv{Z;3?<|4S(SݨH2d8)"mse e_Nx%e5Vp?U *aelusNV2qXkӘ6p*"*so[M>Ɩ!K@4{+8W351X;SeUN$y+378TkNj0e9FpHף2pGν[R崎PE+1N9 Z\$-T:ڒn[WQQ״s\+]qޙŞunTډ ﻈ)GH;;jk 4;~3<:iI8A?HI8A #D <;zN LTĒf )CN JTi'%*pFI8A #$@vNPH;wé®=5iߪ k7"d{省U.畋3t%0S pE?5N{QyzTٹKtj/KPWmzNUlܦTD)}ٺ"<*ikD8kNp Vi:ΡLMKߗQ,pڕ{U[ʠME_Vp½Js]0;7sg8*Znn/8([d8_F8TI8nq-_:`2oprk$N> ggoq2kg#ccq VD TC3n-8N@!pWp8[o\gS )xr8 g.@=cm gqIнtmveyNpY(8E>I '~n<"I8+`:Oƞ8 γiLPf-tqa8>pk$_M}bm:S3+[hɗl w-)Eu\ήqճ Ep:qfp&qp 7:<ƮTO=[GR+S/Mġ8E1_xNRc E9w8#NY#"B": 1cWJi"w+lw2ZWc7KfN'ύUKnfvɢ{ E(s֍NN E؋NxQѳa֊X4߉N;@I8{\Aq)tTHMiR5Onq Mr.QFq:Kjl3OnS™KlP8yB8MZNMl '",E 2n'xB=@iEvF4\At] %T ڙY\A&T :s : fv-s'\pMlUH;N6m`WvQU騾srF65moh;˥‰urz<:xb,]5Ѽ~UnyW3zap;MgX D񝊦4e--Uf$KA5迫(|c-ShN[ ʒ^à54 Dc{V@mن Ny#̍O,<%OW(2p9Of"N(slAӣip2Gu\n*)㐪n`x ۧY3Qg ۑ +.)كSkqC"A3Rz™*%LބpJhI8 7(5!'I>AB)YH d #8Lv5*MFlio=!:;ǩt|ZE7MƚANbpnZ},A<@sE\;՚9C訾2g8uGhMw'cI8 D cbWݷߘNEugvNfqOPs)=I-ːk^EzNd3 5N?2:NZ?8u^EE-}%u)NRm ډ=_NPD<+33pnT%~^V?H >V].Hp̩,Ɖ_B7䝘aܬwwI*>Uv'*ҳ&iNci;U ֯뫳=Ǡa8mzU4B :κ&AQG߶|ͬQB~3ALބpJh. ( Ӿ'Z*)cD-ku?!p▵u<[d )h 'nYHƎ+{NY2J1{ >7OB Sot}^)fB>$z3ᔶ.Kwf8|%*Sg98_;[$oN=Ծ$Uu:Q`fR*EL2:8z㬩RStkC|C1\n2!ޅN|Nh8E_;^>t4K(sM+*_7fT(%N~d{4=§k`0i @:~]?TH/#(m8}($'riq@ 0:~^P/^__"CT_4wk߳f6\z)xr=ɇ }QԉMWوiy2_tdڟ4 #f)TZH`R $iH6PNoŞZ.Qvn qi@bBF:0t$#j$[^=}ۆTgzFØD&1&mDVeZ& Ū@I*AeB4`)%Vj?_2@ w$UtL'b^Ab0N!ŦwEE '\H@Bu:oƓA("UnGuaSC_,ƀ^S-[ 'ҩ#MAOTEHLL@:e9 %YFۭʣ-cS H$ "GO3@cs 0@B#̬,7- $;2nbSwD@RB2T17`-)mD6@ 6bajpɹp)dM4$ SڸJ؁ɜMaa1$}?id+~'P 2ݘ٩t 0 1brUOirI%!z]H-葖H!eu0-6Ǚmf|Z)NTc|6g/ SeNeZm*Wb^i_.jHl݃F h@',^ŶEY#,鷴h@4c57$%߶2~cd7fhqgi`6q10EHSԸ@ V5vXn"Z1RB˷}o ZpHYClFjR+f766hHxrwF^L':ۯ[%+M;Qw7;QE{lwQ@*i},@Ҵ|G:]^׋oVM<|rfehRQ~^ #ի"Ams=*Glb@0&@JDz " MޕO-}v '>zزGqV;/Yj3s631Y7;ai 1[`QS]B H ( N&vlkx3D83ҵE@ 865.L@~(qZȽH'5T;lEP&ڌtJt$1j˨ Rb{f 3}%wOD|0<cġhә\{”G)#RHrāLIjoYv|JTxqy7g$:Au3Oh s^ Rߤ yZH:߼n\YH+~HYKm`i3HHHS44Eѷ'R|"!Z+.HF@8߳ {qn }Y=zQ7>,x~ܨri{__kUoGWnY~˴ [yp6Jbʼnl`iw6b jn = rv ~D)FU ϋ_cFǞ|$3@:tEHI>#'@_ d6g9}w %% ,}:OV)@\"#1xd 1y$;_ hB9 !# "]^8h,V^DW8 !mb!IH$b7ؑ$P٠p಑H%FSFmZ•@OqQOrmU~f(pD}ll Y Єg흙[P0̆?i2UYe[ $A?#AEHAɑeӬyIŔ38 ͍!Ss*g9Mɕi*/^H !L[l^ń3 ҶhDF]){f t1R,fowr!O5+zS`+έvq $ 4d)m9R#.$RS&Eت# [$w"i& NZ"IMw 'Ԁ63]`; H: oȆX*3lH'@Z&͝z@"#nϵlQ/:%-fYxWP%H'\~ӮEm(2:FR$fb"(wgVG$NN3#R= ]VHZ;< ng Q#d+f,Z 쨜QPj`q H.v_ $5&Hř8} :Fu983Rp\hZ_]H@^IxtEQTѝAHsHkF`TYe*|;!"e)w:b۫ҰxYXr ]4: 3u3+E&0$}wd*]GWrx^mgDF=$ 2Ҥi0N~IYP0%/Ip/a}6}8Qݶ\R]X${sEwV/$"N6 꿦DjM)jBWty+QӨ:PFdT {W>ޖAJ(qFiW3eFr@\/wٲ@Bŧ@\>|iNZ{N꿅ə*oȇ^8oW>:C55l_ 3+it/&zA}sM8' '{ҫGJg Uń;1ְLB1OdCM@#M{47Y󹵔ݡ81>=ޔ VQsW>n׳շ5xEFLD>I4$Uڻ}O8{G8L S7t:V0+恓MF*tJ֠4lbտ"F Rnw)AuYj#k+` [mZW0ᆔPb7H GMjFEՍKH}V"8cKg FR?$% MK1c\6wi2A2Gm;c$@#.bbŪ5y$%:o(AI8rnъ#.v`1q/fIJ^_8夯u_PŨr5HS lF F%_pXVׄ,1`vq6Dj i鎿3 E΅{ 8 xW#]'8 %_QE 7lՋGߗ97$$Z*/jr;Ej}@u0% DƴV4l4]MA&jHpѤn-P~EO<_OV"4ru#>\U#*P\U>K .q͸EI.θA ܎`|;Hؘa@[ `CǨsYP;̎:f.ei9BEt֮C@蔑;\i:'wvIi4ͲuLQngqN8/m`y;؟'AF+1ӕɜ6]@*91$l&RVӏ %P&Hj`$T j$C֝)Um)_EDǗ<$ij8iE ${g?__Ot7mUaICs}g{'2VsJOお")1vOR$eD%ZpB`/sA+U&}"aH y$TrC۹3H(Ƈy*, Xd,@QwiNx؟qΣyG.˸2fn۷Ҿ_#9a~jSSiXZ-/?]>،v{EF@ Kj!q\ Jd!qFxd>zZf3o|>$-&|9Ud$D@r';Ҽ|!i5έIY9 ]G՞7 =LjɪvK$9TY E^dbB(s@B^@# ZIz(ZcPb$:rDyFʬq1v1qd#Ws!$#e 6 Ks] MtRR9$o Aj0 #Ҭr$ѳOG11Mً) !bt`BrԖd+bǧp)h1q&`nHu+ۭީ.Fz{H?PYHIlK,&$. 4{sAC'W75;s&=H ζkoVᗭKhR-!!>4ժ\{_n&']f/imɾ-[z BnԚh! O2M@F$ͭާӃX-QљQ#dO9a"=k`Ɖv {#)fpZu MS#@$}CF;fywhvT$^u) ¬-A0H"vS+"XX# HF4n Y7 9L)H'SwD٪t՝zLr R bs5AC me%s |P*B1AMeqt ěgTql=[UuW7?: \g;gga )'Zurr9{ HVI0LaX@e`483xwZ?H SiMGiœC KhQ1 D*<(3T46"#. Owjݰ? SM+ɉ ݦw.-'RҶJym b 2f4PHS[F 8!'X E> S1FP " f.&",j8TB m(^oG5&E[E;Cyd&!oˀCΩ#9H|՘L#XxȶئHlH*,IBL YPd~Q~wBBRx @WG£ZUST~M5#QcjcZ RIGJ" fH.EX?YKS5َ%5`ˇf) $,i4" 8HR9IDIjR @̓yb3Hd ݰpwWVn֨b=˖q7r_ 0Cvf ʯ"' AAMV dG`|W &Hz0sa).!n&c\+J>_lRm[TSfvɇ7aU62mL>ArdfT*!S$zhU0j#ٞlra[JuؾH#m{1:ŭьs*M`|T7CR]'2Rbw4H ، NMhF#<Z YѵPi !+c@X a! JoLWsi~Is,W!M\kVeLHX ԳfeFP.BƱ' ֠" "Aqit(QlWbuk-Z9RE?߲#u *V;CO+(X 9V'| RWH3 '3l'Um;CiOѣc'tLo"΃jDC!b7Řs΋jF'¤@r eTֈhCL{JƵpo I@XX &}\4!&N1yumv IjuOIn1c$jQ7H:pF$F zi⎷!6ؖ,"ѵ4~>R6:"HNܖذu!*062!t1q>_P ?__O[0@"Ӊ~dkB I@(@F8ZRpX~Xa -&m^q,)NHn;z>d2dX6*ITYDOzeFu>T&/ޞS1=l\ԢՀ$R^w݌Ɏ8GnVR \7t6VG.l::.}RP}NVh+-̺l F]H[S7;d.e":L#sGB䥝ڕWVy=2Lwg56Z}9Eih{:;ً,84j#!vR,@GCcn밧ڀq+yb].Hx IFIS+C̤N+i=k8] 64v!gw#?jF:>ru3[V sgn Egmg.xLWm!Mؽ#eog<h꿿Umk(~W>5jTvJ_:VEh8Фe&]@κAM C.&NcMwmL7i lFڠ"#/%XA\J J.wH@^kሤimTS0iH[PnW1bDwk np_#A7(]Y$UXs@rQ  /",#\,?*e{=H@3MN} )%\t7NT7i.t2'f: HEyrY}5_Tæ4$7`CzTMȩY],2U_QH| (x<DvE -vdG W˪eF;"S+7^kq8(d}$TP$~?lCQҪ~|wL,#[+t'XӲtZg) fg.H&NJABq~HÒ:r>i-PK[qn {6s5aD赪سٴx,g*Gm7N5b_i{둧M\(bP&uui2>+_$hS1ɒKsYCYA~0Fk'hX1!.x+wf$r.:R{ӽ#ݶ@Pp,/j`=LҞͰ:: ]|J +CXcAV/a)MHmxz2X;D[> $꠼;ŠWwLDRdFu$ɕfe[(.;|`};:O2m@"@A $}@]]R^S$#eיȯdyo#@tz 5mG XW7(ew u;r& vArQoeLkR+y:w@p%Eq=f403pR;5ՙ $_Y &@~\2;Zj$ lcƋ@AvICSyJ15(*GR HgW"ܗ)dZ N%͔ 6 qg- z%SRTFNH&hčjD\1\b͒00Fs5I<5Oǰ@U&wނ߉H3HYwdP73:GM{R(j/r橰uޏ"ii*E6D$B4,ƎY\.I J5v,i_+<q$b^ᬣR\l,^c9 ŞYL5/,, )qjbԆpaj1('$ં^0|$;HvK}H6"_R%jgF w- `tAG2}a\A:b $R -QW84KgżѓvLG ʌ#kA+1F L98U)eW&;9)btb[3+kdP/&ΤUiRq#5f :+tQ/b moKs#pY˃+J}uu-Chcq~l,k^^ܮixl9ukr0&sKk3u50@R,#H|eq$[^һ6 $+b@4 Cm3ԨҐ1G"Kh8t,0RyV "JZ^סQ8 <-3] |v|Y2OD $:ҫirg ivGHx-O`$U"Oo` b1G zFdxgȤo|hAǙЂ$mj=nz#A@T/$<"O $  '}K`Z$$8=̑/D?GH@Zd#ȢU׺6nȓC*lc Okzl?o:N"s6G{I>P#*8MfE 2oK[ϼU $*C37L78E;*{ սH]N^HY{g) 3ϐӘ@.Px4R9Ȉ⤎tI(RR\Ò T.E}  tfB eAqMC:šq McH8aXsC9gH82;q."1`ĨRcۇc$Wr $~2Rtd }J_;C9fdOW:HvJ,f>18OY|A ~Ӟ V:ڀq?2+~>1 OM;䇕 vwkqFB-@zOR8WEmh~ԶK3-dV G)t`$dr> e} ,1"m4&(#db 67gWKtgxh{>/3R4 G=6[rf --@zC aWQ:qZBI03Di3]#IWoߦtC`D! IBzWҴEm&(=Oymn&Ēv2;(6]2!`@?kPph0, $养\1 ٩/# | aQN -'cyl+H9HU=;>= Ngj pTKjHHI68Mksne$yOiHV)qGTRSSӾپT:>"C'GCP"EzoI꿓}Dw>u<=_bܣҨ]@Zryio|1qް0E%ܞh`jiI76$e'$7!6f9?v'xm:y'*u ѐT J쬦pT_ $i_D=Ł8 ii>f ۼ4Y ; CKڴowWm T" TT9K^nő+ T@L]C9T s&iTNj &\wţMo)6Tm/^ %WJ4QswFBǀVՑ0]B49$Dr_"фiBL~0?(/}eaX7ѳXzmϪV9! ^W@g™!%dօ;<7TAHt$JWڟ'ݲۚĆ/F:BbuV jWV3;C u8jζ1gD[ԦؾHuQq@ƂYɯa~:ɠy8ݕtHQW +q:`^FН%L!{z76޲R 5GiXCSv!Y k`ia$6~HI~X"6A $k}+V$փ%z$ڨs_hRZ ġh!b1ŝ Wkg{ԱI[DݏU8z~ߖmݛt0}2>Q xeXsj4!tj%?$l޳nL#&Z  4G0`R:bH'Ea_QSkˉh0 H$oA@DC%c FP_扈 9na]Hj^[tlSSq'41yV_ݟFF,K#ӄs*sz-Ʉ?PH8h:qiPTzT]5=HˏK;|eiz佶 j㜑qw3E``4;S-֕U) JBgR@2hyl$ $dr%9{H9;9 1^ig,TDo,dAQ#dNib NV?#%H{@1]JYȋ)94^22EUB )5 1}O `$vo゚4ؿoޓ^PH#=Hc w\yhO}QK#a(;s1`$ThPm;6shʹ3!jܴt#.ZkӨMB@gkc=㣀ԣue `{>q# Z.i@t8ݹG=k{E6H g^L%'Wi1~j]pT% _qr_at1$emv#t휫as1:HN#&G#eoQ6_hMKQm5ۑ}H!{HwkC/G-ek1/?Gǽ_"I w35qz?Lvご1=W 5H!-?H-u0R>R'$'ZHᢛڤ~HT$~Wt?^3Fb$E@;$bτP ##΁H 0628r>RQGzT;jttGm<3:$8mGTI"m|K$ +g;I G_}Z[S#~)}[0g^R-qR00A>(KMOP03BJFIENDB`"Ddr   S Ahttp://www.blong.com/Conferences/DCon2001/VCLvsCLX/EventTrace.gif b!el.a3h6ա!Tn}!el.a3h6աPNG  IHDRnPLTE`$)wH $`P8w*wwH $,y @< 1<Ȥ$<04wȤ<<wPwL5Qw<1<0|w<1<0,y1< dNwmH|&v<Rw&v<  nHH˳B<&vOf5%$y/kQ_?$bS%rADTl ݾk >V&RQ$Z"b|p=i(kڞuLFX۵X],Xͅ^_zϏ~W!fSFTbFi Ѓ&{BpSJ*)BpAUJMmjJN*:CHی.:XG㖙#iVe.X_\-HT&ikI"{͝w3X9~$6ekDM#18B k?VC>DcR Bb^`Ck`+gXYʋUlJ#SVƬŏ]yx~ >]F衳瑒lc? Id1ìDS+t(7ͮG߿E ؅Nz*2xL Xy`DRT$`yX1rNF 0b)Q6ˬ"BcubӐݾ5+?Kj?9tgg `dEm5e1'/FP,d*T5fx[_LR"XN^~CFS=bN+ˏwy"iLj1# @"@c  v؏-XQL^A ~@/Ƚ=hEj m& ,ING⛄!\O?C"-hAk-k^ukC?ي?kj "% wmC QX1:hUㇸY~$U;ԃԭronyߥ~q+?(r|RZ_JWx~i^~;о?-]ُVʗG% QRm`s?l]n$hK\ `+{hd!X*a薯1.a[H9}nKeګY'8m5$O_5oZwj7B_~oT$JG`$"83qc?ޕf|?h1]iE7V?IG, O|pO|D*hre#]xy-꺺r^GFf}ŏp"Y})hd?/JӍt ...X=~ S8#Ү1p稕];h]d>|di/>dqɝin??G j]diS@mbn??EdGQYy*tKJrbϯh5S1d31a@c.c9˵PfaV VばSf?J.eTqEA`? q!e\OPZno9[u(..-Q=~z`G'?$VBfsL /G!q@>^Z~g{XR?&Rj??ú^/]V .g#q&џ!PkxW^ۏirtPDt9` =`mI‰+@<M1vHr?hAZ!\²J] ǨPH#񽈕h?dA0e h0Cu8v8[pw|^`?nĆ8 [Ss?T\k-VeӶĢz!Mm/3?R>#K6p }՘!%"iWUڏ^ a!#s?fcm~t$k_8Z8[Ƥe,u1%C 5j?1WknjmE|G"<)v_eԀM#?z_gW>Q6y 0Cuq@ةLSBcA2 Wʅd2'J~ z:;Uzt܅Q1:z*Olka'<"S<ƈ[pRͿ2Oq>g^@ ؆42ee:5D>Twx}9Tjp>Á1l5~ c*ܷkƏ) v`_'Dq[m ^ "a?L0ݯ$~o؄a鵅ת4pk UimL_Jz=G?_݂jB4pGBĿ*(Sp3&ɇo6'Z厎pwo~Nn"-@0pXá^1 k.ZN: չܷQ!BhKuRi{cRNmh[88?V%O_ʣ&T#T}[o׫O+b,S10ƒQ3 P\&\iA}ˎ[4ӠeG-vDO;AH~ëb9!A1[L4oQ-.'qX!V,/3I3,qmᠮXx8c×B^PnC:W^߾U F%UIrFL<?9iG)_b$S,361& f&=,Z&; "GܪǞއ,.q[[פ[Ə# "n`(1;^BrQ[_J!9eg~Kǒw#ܪ8|DE>#9?FxR:6# $% ] I֠ 4iP>!j6(clxZ -vq :tJZp~5ʸ-'rGaM|| u ?(Dڒ!WlעcP!j6(clxZ -鶒E4O?WL GU>_G΁ag+'0cL-BMktw7&B-![Ə9v@ĴU$1rŭ6K>aH?&x~kCc2ƒm!"Z_F 9!f6Sj-qJ`u~Bk!01 G6~ous:q.?źbu0` ?,|G/;*%g:= lyrm}MzALX0tTlX |`~0z(߷ ?h|=$F~dOY.bTCvOOI^x6j}:@+ipYQ?&R`R^ ԷV%ΰfm?x`e#yzUMurAhҐu" ?5u)jljh@<:?LY?j^#:I8WhviP߲#j;Mh4oqK&t[##u@U$ a>QLq\k'0}:R.j ޽NP DJ!??>/8SOp / ##cVE}_k^q-p?U9l)?NhܪǞއx7чBd5~ Nbʞ%fuy\Ta1?eX[_W._|/6J?OOuZOc#Nc?(RZ [1E\v&a~&~&L-~V&^[xModlcS{7(:?LS?(OTŸ1 EH]͡?x'? 8`/k|OO|2]Ag͆3cLX IY??'tJUmX!-gޗ=1؆V 6J1xخ/QӍ*RfPekPQIbҤ oi^r4{:Ji~?8O? Ⱦ%jN5űۋOv92!PI6`_I! k Ui ?^z&?;MTxIZgo?bO\X]0ZkmG81CA-)߱R\s9§52@~46~ i<ߴАA/uקTFۛA\??_CGX&x=CB߳rS?$u8,#hc~`^ǔnQTfpÍN[7;m߻׫Obޝ Y0 &nW;z-6` lzEs͆ǟ+~AKZ_~ȏ?njK\F؏U&NKj5DD}m\}i@ #VEX.l2BŃNr,Պ, _??]d7pK[3ֿ_LXؠèNմ~ âeZ8vdQe",p,a}{0?WY칬_Zp3Tojcѣj?]F2#D3 äG~xJdWoȊdLҪր@ ڨ_ o+!]-] 1dzQ} bPk=\Vwsz-h_՚6xB~T%v71奚1-*7"P>G?F" 5C;&o P)YV~n+@=-'Fj `IENDB` i@@@ gQe1$$CJKHPJ_HaJmH nHsH tHR@"R jL 2dd1$@&[$\$"5CJ$KHOJPJQJ\^JaJ$R@2R jL 3dd1$@&[$\$"5CJKHOJPJQJ\^JaJJ@BJ jL 4dd1$@&[$\$5KHOJPJQJ\^JR@RR jL 5dd1$@&[$\$"5CJKHOJPJQJ\^JaJA@ -k=W[W"U@" #P} >*B*phJ^@J gQe (Web)dd1$[$\$KHOJPJQJ^Je@ HTML Preformatted: 2( Px 4 #\'*.25@91$CJKHOJPJQJ^JaJ'=jt2oXEo.\ )jj%IQ [bp]mS R!!!!#######v$w$$&%8%%%W&&'g''Q((9))**)+++,,R--?../i////11273D34568:U:]:;<"<.</<6<u<v<~<<<<<<<==%=P=Q=W=o=p=y==========9>:>B>l>m>u>>>>>>>??"?O?P?V???????@@8@@pAAAAAAAAABCDjFiGGGGGHHBHIHNHVHZHxHHHHHHHII!I*I4II*KLNOaPQTdTTUUVXZ[!]Z]_]{]]]] ^H^p^^^^-_R_|__`axaa&bbbeKePe^ebefe{eeeeeee+f@fkfpfqfffffgXh`h!ijluno,qrt7vywKxx yy#{{$|||^~[)W%цCu!Љ[,ԏtڐNג)*QǕ ֗PTg5 uV]$0&>X1vϩ,<KUcsȪ֪ *=TexիݬY_&svs׷[\zE..3Nt7imH !>Hgs >Db>=>[e)04&+q;W[c*/GOYy+1^cd 7`fm)-@Fb{W-HMQ7e,`%*AK#,ahlGrx 9pJ]bjVwi1)yAEEwP/ 5 S q    F S X }   D-2Cj07;]cGT56de Ly~5:/?4a [!H"Z"#$ '''0000j0j0j*0000 0 0 00 0 0 0 00 0 0 0 0 0 0 000000000000:0 0 0 0 08000000(0000000000000 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 00000000000000(00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000(00000000000000000000000000000000000000000000000000000000000000000(00000000000000(0000000 0 0 0 0 0 0 0 0 0 0 0 0 0 0000 0 0 0 0 0 0 0 0 0 0 000 0 0 0 0 0 0 0 000 0 0 0 0 0 0 0 0 0 0 *00_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_*00ƙ0ƙ0ƙ0ƙ0ƙ0ƙ0ƙ0ƙ0ƙ0ƙ0ƙ0ƙ0ƙ0ƙ0ƙ0ƙ0ƙ0ƙ0ƙ0ƙ0ƙ0ƙ*00e0e0e0e0e0e0e0e0e0e0e0e:0eJ0@0r0r0r0r0r0r0r0r0r0r0r0r0r0r0r0r0r0r0r0r0r0r0r0r0rJ0@0Լ0Լ0Լ0Լ0Լ0Լ0Լ0Լ0Լ0Լ0Լ0Լ0Լ0Լ0Լ0Լ0Լ0Լ0Լ0Լ0Լ0Լ0Լ0Լ0Լ:0e0J00`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`J00V0V0V0V0V0V0V0V0V0V0V0V0V0V0V0V0V0V0V0V0V0V0V0V0V0V0V0V0V0V0V0V0V0V0V0V0V0V0V0V0V0V0V0V0V0V0V0V0V0V0V0V0V0V0V0V0V0V0V0V0V0V0V0V0V0V0V0V0V0V0V0V0V0V0V0V0V0V*0000000000J00J0J0J0J0J0J0J0J0J0J0J0J0J0J0J0JJ00000000000000000000000000000000000000000000000000000000000000000 08 08 08 08 08000000'*0!@Dh͒H\%+%9-D7u@oAlBCEM bi#ez4@,b5 L +++%;2i&loEd *L5w} bh~.4J_r3 @ ]  / q w  R X n 7 = S   $ g { <Tp&H&hn ^dz sq!!!"L"b"####4$t$$$$$%#%8%%%%%%%L&T&W&&&&' '']'d'g''''1(N(Q(((( )6)9)))))**r****'+)+++++++X,,,,,,K-O-R----8.<.?....../V/f/i/// 2u222238@@@c{ccxyy$|||%[TdSiDDNQ0"$>H ?4 a   [!!!Z""""""K$$$$$$$\%%%%%:&g&q&&&'f'''''''XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXCXCCXXXXXXXXXCCCCCXXXXXXXXXXXXXXX<=BCIjstxy}S'!!!!##>0C0334 4^4c4'71777)8.899U:\: ;;9;@;k;o;q;u;w;;;;;;;;;; <<m<t<v<}<<<<<===$=====/>7>:>A>>>>>>>?!?????"@'@(@/@@@@@AAABFFGGGGGGHH,H/H7H:HVHYHHHHHI I*I3IIIJJ.K7KKLTLLLOOOOPP'P2PPP^PQQ*R0RKRURUUpVzVa]d]m]t]]]]]]]]]]]]]^^^^(^4^=^E^P^X^a^i^z^^^^^^^^^^^^___&_3_:_C_K_Z_e_n_u_____H`S`e`p`````aa"a4a=aEaMaVaYaeaqavaaaaaaaaaaaaaabbbb$b0bGbPb\bbbbbbbbbbbccccKdVd|ddddddddGͣڣ$15>@GITV[]dfpr fnŨ˨Ψ֨]nv~Ωϩ+,;<JKTUbcrsǪȪժ֪ߪ )*<=STdewxԫի߫0<EQ_g&1QZέڭ Yb,eqͰڰ @JS]αױ$@N&7CVbô˴ִ!*-9=KN`drs׷ %'47FmoֻƽGMipMTV] ' !)296QSprHTXb/6(3<t} $+ #,5<LVXe%&)3;R[fo{ )0@IRYisu} '=R[cls DXRY]h4> @E]kmw''  0<O S ##=(M(AAGGGGGGHHHHHHDHGHIHLHVHYHZH]HxH{HIIII+LLNNdTvTUUZ]^]g]m]]]]]]] ^^7^=^[^a^^^^^^^__=_C_h_n___a!axaaaa&b/bbbccKeOebeeeeeeeeeee ff-f3fJfRfkfnfqfzfffffff!i*i{kkll 2Bךٚ.5w5  /5@Girw >CFHfpLR]d+.4<&)*.:@QX}+03D^adm ";Pbehlqs),@Edk.Yk/>HK#KQ{GM%)%+09cflu)X_twz~")r'+LU]`y / 4 7 9 W a s u     H Q S V   -1?I!*GPnw25;D]begIR:B y|58'3333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333jti//'test2=C:\Documents and Settings\Administrator\Lhb\VCL versus CLX.doc 7b&4| .__4^ N,Α/[-:mB'4VD*GTtH?j or^`CJOJQJo(^`CJOJQJo(opp^p`CJOJQJo(@ @ ^@ `CJOJQJo(^`CJOJQJo(^`CJOJQJo(^`CJOJQJo(^`CJOJQJo(PP^P`CJOJQJo(^`CJOJQJo(^`CJOJQJo(opp^p`CJOJQJo(@ @ ^@ `CJOJQJo(^`CJOJQJo(^`CJOJQJo(^`CJOJQJo(^`CJOJQJo(PP^P`CJOJQJo(^`CJOJQJo(^`CJOJQJo(opp^p`CJOJQJo(@ @ ^@ `CJOJQJo(^`CJOJQJo(^`CJOJQJo(^`CJOJQJo(^`CJOJQJo(PP^P`CJOJQJo(^`CJOJQJo(^`CJOJQJo(opp^p`CJOJQJo(@ @ ^@ `CJOJQJo(^`CJOJQJo(^`CJOJQJo(^`CJOJQJo(^`CJOJQJo(PP^P`CJOJQJo(^`CJOJQJo(^`CJOJQJo(opp^p`CJOJQJo(@ @ ^@ `CJOJQJo(^`CJOJQJo(^`CJOJQJo(^`CJOJQJo(^`CJOJQJo(PP^P`CJOJQJo(^`.^`.pp^p`.@ @ ^@ `.^`.^`.^`.^`.PP^P`.^`CJOJQJo(^`CJOJQJo(opp^p`CJOJQJo(@ @ ^@ `CJOJQJo(^`CJOJQJo(^`CJOJQJo(^`CJOJQJo(^`CJOJQJo(PP^P`CJOJQJo(^`CJOJQJo(^`CJOJQJo(opp^p`CJOJQJo(@ @ ^@ `CJOJQJo(^`CJOJQJo(^`CJOJQJo(^`CJOJQJo(^`CJOJQJo(PP^P`CJOJQJo(^`CJOJQJo(^`CJOJQJo(opp^p`CJOJQJo(@ @ ^@ `CJOJQJo(^`CJOJQJo(^`CJOJQJo(^`CJOJQJo(^`CJOJQJo(PP^P`CJOJQJo( VD/[-7bN,TtH:mB| __4j o J:$Ælr5TS\'x4^: nн62,7!8h;~<|'2Dmdcl6vteLkh"-ln):bw, \~\ .#TLhvK0l6~dV&J-(C (܊,nX?TPX@ A4ƮnȗOL7~:TRQ./F *t$72 I\-b(&lfq"PFMVTDtZXdϦ:),xp<"<.</<6<u<v<~<<<<<<<==%=P=Q=W=o=p=y==========9>:>B>l>m>u>>>>>>>??"?O?P?V???????@@s׷[\'@##j##'`@UnknownGz Times New Roman5Symbol3& z Arial7&  Verdana?5 z Courier NewI& ?Arial Unicode MSC.e0}fԚPMingLiU;Wingdings 1hSS*|#?!),.:;?]}    " % & ' 2 t%00 0 0 00000013468:<>@BDOPQRTUVWZ\^ \]d([{  5 0 0 00000579;=?ACY[][77x2+2Q http://wwwtest2test2Oh+'0p  , 8 DPX`h http://wwwttptest2/westest Normal.dottest2.d3stMicrosoft Word 9.0@F#@p~dL@L*՜.+,D՜.+,4 hp|  1/|+  http://www D@E 8@ _PID_HLINKSAD^RDhttp://www.paperfolding.com/DWAhttp://www.juggling.org/-u>#http://www.borland.com/delphi/votei ;http://www.computingnet.co.uk/D8"http://www.thedelphimagazine.com/0z5[http://www.amazon.com/exec/obidos/ASIN/0201593831/qid=905701291/sr=1-1/002-9464178-4139807O2http://www.blong.com/Y /5mailto:%62%72%69%61%6E%40%62%6C%6F%6E%67%2E%63%6F%6D|0,http://www.borland.com/Y )5mailto:%62%72%69%61%6E%40%62%6C%6F%6E%67%2E%63%6F%6DF&:http://community.borland.com/article/0,1410,22495,00.htmlI#:http://community.borland.com/article/0,1410,27231,00.htmlD "http://www.thedelphimagazine.com/z,Ihttp://www.delphizine.com/features/2001/01/di200101rk_f/di200101rk_f.asps-Ihttp://www.delphizine.com/features/2000/08/di200008rk_f/di200008rk_f.asp4http://www.blong.com/Conferences/DCon2001/VCLvsCLX/Styles4http://www.blong.com/Conferences/DCon2001/VCLvsCLX/NetCLX4http://www.blong.com/Conferences/DCon2001/VCLvsCLX/NetCLXmf4http://www.blong.com/Conferences/DCon2001/VCLvsCLX/ VisualCLX4http://www.blong.com/Conferences/DCon2001/VCLvsCLX/DataCLX4http://www.blong.com/Conferences/DCon2001/VCLvsCLX/NotificationsVsSignals4http://www.blong.com/Conferences/DCon2001/VCLvsCLX/NetCLX4http://www.blong.com/Conferences/DCon2001/VCLvsCLX/DataCLX4http://www.blong.com/Conferences/DCon2001/VCLvsCLX/DataCLX4http://www.blong.com/Conferences/DCon2001/VCLvsCLX/InjectingNewCLXHandler18@http://www.blong.com/Conferences/DCon2001/VCLvsCLX/VCLvsCLX.zipgz4http://www.blong.com/Conferences/DCon2001/VCLvsCLX/FutherReading4http://www.blong.com/Conferences/DCon2001/VCLvsCLX/ AboutBriangz4http://www.blong.com/Conferences/DCon2001/VCLvsCLX/FutherReading4http://www.blong.com/Conferences/DCon2001/VCLvsCLX/Summaryfo4http://www.blong.com/Conferences/DCon2001/VCLvsCLX/NotificationsVsSignalsCLXs`4http://www.blong.com/Conferences/DCon2001/VCLvsCLX/NotificationsVsSignalsVCL4http://www.blong.com/Conferences/DCon2001/VCLvsCLX/NotificationsVsSignals4http://www.blong.com/Conferences/DCon2001/VCLvsCLX/InjectingNewCLXHandler 4http://www.blong.com/Conferences/DCon2001/VCLvsCLX/InjectingNewVCLHandler 4http://www.blong.com/Conferences/DCon2001/VCLvsCLX/InjectingNewHandler4http://www.blong.com/Conferences/DCon2001/VCLvsCLX/OverridingCLXVirtualHandler4http://www.blong.com/Conferences/DCon2001/VCLvsCLX/OverridingVCLVirtualHandlere}4http://www.blong.com/Conferences/DCon2001/VCLvsCLX/OverridingVirtualHandlerpy4http://www.blong.com/Conferences/DCon2001/VCLvsCLX/WindowsMsgsVsQtEventsmv4http://www.blong.com/Conferences/DCon2001/VCLvsCLX/TheLifeAndDeathOfAControl4http://www.blong.com/Conferences/DCon2001/VCLvsCLX/Stylesot4http://www.blong.com/Conferences/DCon2001/VCLvsCLX/ VCLvsCLX`}4http://www.blong.com/Conferences/DCon2001/VCLvsCLX/WhatsNewInCLX4http://www.blong.com/Conferences/DCon2001/VCLvsCLX/WhatsNotCrossCompatiblej~4http://www.blong.com/Conferences/DCon2001/VCLvsCLX/WhatsNotInCLX4http://www.blong.com/Conferences/DCon2001/VCLvsCLX/NetCLX4http://www.blong.com/Conferences/DCon2001/VCLvsCLX/DataCLXmf4http://www.blong.com/Conferences/DCon2001/VCLvsCLX/ VisualCLX4http://www.blong.com/Conferences/DCon2001/VCLvsCLX/BaseCLXvy4http://www.blong.com/Conferences/DCon2001/VCLvsCLX/ WhatIsCLXvf4http://www.blong.com/Conferences/DCon2001/VCLvsCLX/ IntroductionOhttp://www.blong.com/4http://www.blong.com/Conferences/DCon2001/VCLvsCLX/ AboutBrian#%@http://www.blong.com/Conferences/DCon2001/VCLvsCLX/VCLvsCLX.htmg http://www.blong.com/Top .http://www.blong.com/Downloads/DinoSource.zipY 5mailto:%62%72%69%61%6E%40%62%6C%6F%6E%67%2E%63%6F%6Dvi~,http://www.blong.com/Downloads/DinoSaur.zipLV{http://www.gexperts.org/= x+http://www.eagle-software.com/coderush.htm]u9http://ourworld.compuserve.com/homepages/mikes/TRex.htmlZr(http://www.blong.com/UserGroupTalks.htmCOM(:o4http://www.blong.com/UserGroupTalks/BUG19980423.zipIl(http://www.blong.com/UserGroupTalks.htm Components/:i4http://www.blong.com/UserGroupTalks/BUG19990223.zip;?f(http://www.blong.com/UserGroupTalks.htm Classes2/:c4http://www.blong.com/UserGroupTalks/BUG19990223.zipI`(http://www.blong.com/UserGroupTalks.htm Components2-8]4http://www.blong.com/UserGroupTalks/BUG19990506.zipH Z(http://www.blong.com/UserGroupTalks.htmClasses-8W4http://www.blong.com/UserGroupTalks/BUG19990506.zipR T(http://www.blong.com/UserGroupTalks.htm Interfaces-8Q4http://www.blong.com/UserGroupTalks/BUG19990506.zip7pN(http://www.blong.com/UserGroupTalks.htmMessageInABottle2$9K4http://www.blong.com/UserGroupTalks/BUG19990319.zip7pH(http://www.blong.com/UserGroupTalks.htmMessageInABottle.:E4http://www.blong.com/UserGroupTalks/BUG19990525.zip7`B(http://www.blong.com/UserGroupTalks.htm DragDrop,0?4http://www.blong.com/UserGroupTalks/BUG20000321.zipC<(http://www.blong.com/UserGroupTalks.htmActions(094http://www.blong.com/UserGroupTalks/BUG20000523.zipZ6(http://www.blong.com/UserGroupTalks.htmClinic#334http://www.blong.com/UserGroupTalks/BUG20000815.zipW0(http://www.blong.com/UserGroupTalks.htmDocking)2-4http://www.blong.com/UserGroupTalks/BUG20001017.zip&j*(http://www.blong.com/UserGroupTalks.htmLists.1'4http://www.blong.com/UserGroupTalks/BUG20001121.zipL $(http://www.blong.com/UserGroupTalks.htmSpeech$0!4http://www.blong.com/UserGroupTalks/BUG20020820.zipC(http://www.blong.com/UserGroupTalks.htmNETInteroperability(34http://www.blong.com/UserGroupTalks/BUG20030114.zipP(http://www.blong.com/UserGroupTalks.htmDiggingIntoNET.34http://www.blong.com/UserGroupTalks/BUG20030211.zip!k(http://www.blong.com/UserGroupTalks.htmInfoResources*24http://www.blong.com/UserGroupTalks/BUG20030403.zipG^ -http://dotnet.borland.com/samples/Digger.zip|9 http://www.blong.com/ArchaeopteryxSource\http://www.blong.com/ArchaeopteryxP"http://www.blong.com/Articles.htmOhttp://www.blong.com/jqD?http://www.blong.com/Conferences/DCon2001/VCLvsCLX/BaseCLX.gif}Ahttp://www.blong.com/Conferences/DCon2001/VCLvsCLX/dbExpress.gif"7<http://www.blong.com/Conferences/DCon2001/VCLvsCLX/Indy.png#;@http://www.blong.com/Conferences/DCon2001/VCLvsCLX/StyleWin.gif# Ehttp://www.blong.com/Conferences/DCon2001/VCLvsCLX/StylePlatinum.gifQA Bhttp://www.blong.com/Conferences/DCon2001/VCLvsCLX/StyleQtSGI.gif!& @http://www.blong.com/Conferences/DCon2001/VCLvsCLX/MsgTrace.gifJX  Bhttp://www.blong.com/Conferences/DCon2001/VCLvsCLX/EventTrace.gif  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abdefghijklmnopqrstuvwxyz{|}~Root Entry FpLData 1TablecWordDocument2SummaryInformation(DocumentSummaryInformation8tFCompObjfObjectPoolpLpL  FMicrosoft Word MSWordDocWord.Document.89q